CodeBlanks Logo Icon CodeBlanks

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.

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

Main.java
// Define the Counter Singleton class
// Add increment and get
// Print the count in main

Sample solution

Main.java
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

Main.java
// Define the Coffee interface and SimpleCoffee class
// Wrap with SugarDecorator
// Print the cost in main

Sample solution

Main.java
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

Question
Shape s = ShapeFactory.create(____);
Answer
Shape s = ShapeFactory.create("circle");

Explanation: The type parameter is a string.

All lessons in Advanced