Java
Summary - Design patterns
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.
Exercise 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.
Show example 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());
}
}
Exercise 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.
Show example 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());
}
}
Test yourself
-
Which pattern ensures only one instance of a class?
- Factory
- Singleton
- Observer
- Strategy
Show answer
Singleton — Singleton gives the single-instance guarantee.
-
Complete the Factory create call
Shape s = ShapeFactory.create(____);
Show answer
Shape s = ShapeFactory.create("circle");
Next lesson: JUnit basics