Summary - Design patterns
- Java course
- Advanced
- Lesson 42/82
- 5 min
Combine Singleton, Factory and Strategy to write a payment system.
Summary - Design patterns
In this group we saw five core patterns: Singleton for one instance, Factory for object creation, Strategy for swapping algorithms, Observer for notifications, and Decorator for wrapping. Each solves a different problem.
Which pattern you pick depends on the problem: Singleton for a single access point, Factory to hide concrete classes, Strategy for a varying algorithm, Observer for state notifications, and Decorator for dynamic behavior. Now we review two patterns with small tasks.
Choosing a pattern
Patterns are a tool, not a goal. Do not force a pattern that does not solve the problem; simple code is sometimes best. A pattern is added only when a real flexibility is needed.
Example: with a single payment method, Strategy is unnecessary; with several methods and runtime swapping, Strategy makes sense. Likewise, with a single concrete class a Factory is too heavy. Patterns separate the varying part; they should not add complexity where things stay fixed.
Practice Singleton counter
Write a Counter Singleton class with private static Counter instance, a private constructor, public static Counter getInstance() (create the instance on the first call), a private int count field, and void increment() and int get() methods. In main, get it with getInstance, call increment twice, and print the get result with System.out.println.
Starter code
// Define the Counter Singleton class
// Add increment and get
// Print the count in mainSample solution
class Counter {
private static Counter instance;
private int count;
private Counter() { }
public static Counter getInstance() {
if (instance == null) instance = new Counter();
return instance;
}
public void increment() { count++; }
public int get() { return count; }
}
public class CounterDemo {
public static void main(String[] args) {
Counter c = Counter.getInstance();
c.increment();
c.increment();
System.out.println(c.get());
}
}Expected output
2
Practice Coffee with a sugar decorator
Define a Coffee interface with int cost(). A SimpleCoffee class returns 10 from cost. A SugarDecorator class implements the Coffee interface; its constructor takes Coffee inner, and cost returns inner.cost() + 2. In main, wrap with new SugarDecorator(new SimpleCoffee()) and print the cost() result with System.out.println.
Starter code
// Define the Coffee interface and SimpleCoffee class
// Wrap with SugarDecorator
// Print the cost in mainSample solution
interface Coffee { int cost(); }
class SimpleCoffee implements Coffee {
public int cost() { return 10; }
}
class SugarDecorator implements Coffee {
private Coffee inner;
public SugarDecorator(Coffee inner) { this.inner = inner; }
public int cost() { return inner.cost() + 2; }
}
public class SugarDemo {
public static void main(String[] args) {
Coffee c = new SugarDecorator(new SimpleCoffee());
System.out.println(c.cost());
}
}Expected output
12
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Which pattern ensures only one instance of a class?
- Factory
- Singleton Correct answer
- Observer
- Strategy
Explanation: Singleton gives the single-instance guarantee.
2 Complete the Factory create call
Shape s = ShapeFactory.create(____);
Shape s = ShapeFactory.create("circle");
Explanation: The type parameter is a string.