RizTech Academy logo
RizTech Academy
Design Patterns in PracticeLesson 1 of 725 min

What a design pattern really is

A design pattern is a name for a solution you were going to arrive at anyway. That is the whole idea, and almost everything that goes wrong with patterns comes from forgetting it.

In 1994 four authors wrote down twenty-three arrangements of classes that kept appearing in real systems. They were not inventing them. They were cataloguing what good programmers already did, so that those programmers could say "decorator" instead of describing the arrangement every time.

Patterns are vocabulary, not architecture

Consider explaining this to a colleague:

"I want a class that wraps another object of the same interface, adds something before or after calling it, and can be stacked so several of them compose."

Or saying:

"A decorator."

That is the entire value. A shared word for a shape both of you recognise, which turns a paragraph into two syllables.

It follows that a pattern is something you notice, not something you plan. The code is written because the problem demanded it, and afterwards somebody says "that is a strategy". The failure mode is the reverse: deciding to use a pattern and then bending a problem to fit it.

What that failure looks like

// Three files and an interface, to add two numbers.
public interface Operation { int apply(int a, int b); }
public final class AddOperation implements Operation {
    @Override public int apply(int a, int b) { return a + b; }
}
public final class OperationFactory {
    public static Operation create(String kind) {
        if ("add".equals(kind)) return new AddOperation();
        throw new IllegalArgumentException(kind);
    }
}

Versus:

int total = a + b;

The first is not more professional. It is four indirections that have to be followed before a reader learns the code adds two numbers, and it will be extended the day somebody needs subtraction — which may be never.

A pattern used where it is not needed is worse than no pattern, because it costs the reader everything a pattern costs and buys them nothing.

The test: what varies?

Every useful pattern exists to isolate something that changes from something that does not.

Pattern What it lets vary
Strategy the algorithm
Factory which class gets instantiated
Decorator what happens around a call
Observer who gets told
Adapter which interface the caller expects
Builder which fields are set, and in what order

So before reaching for one, answer: what is varying here, and is it varying today?

If nothing is varying, you do not have a pattern. You have indirection.

If something might vary later — and it usually might — the honest answer is still to wait. Refactoring to a strategy once you have two real algorithms takes twenty minutes. Guessing wrong now costs every reader between now and then, and the guess is frequently wrong: the axis you thought would vary stays fixed and some other one moves.

Java already has most of them

This is the part that makes patterns feel less mystical. The JDK is full of them and you have been using them since module 1:

List.of("Priya", "Arjun")          // static factory method
new BufferedReader(new FileReader(path))   // decorator
Comparator.comparing(Delivery::date)       // strategy, as a lambda
Stream.of(a, b).map(...)                   // builder-ish fluent chain

Arrays.asList is a factory. Collections.unmodifiableList is a decorator. Every Comparator you pass to sort is a strategy. An ActionListener is an observer.

You are not learning something new. You are learning the names of things you already do, and where they come from.

Modern Java changed which ones matter

A lot of pattern writing predates Java 8, and several patterns existed to work around things the language could not do. They are much smaller now:

Strategy was a class hierarchy. It is now a lambda:

// Then
deliveries.sort(new DateComparator());

// Now
deliveries.sort(Comparator.comparing(Delivery::date));

Command was an interface with one method and an implementation per action. That is a method reference.

Singleton was a chapter. It is now mostly considered a mistake, and the next lesson but one explains why.

Builder got smaller for data classes, because records give you an immutable carrier for free — but is still the right answer for anything with many optional fields.

A pattern that is one line of modern Java is still the same pattern. It just no longer needs a diagram.

The ones worth knowing

This module covers six, chosen because a Java developer in their first job will meet all of them in the first month:

  • Factory methods and builders — making objects when a constructor is not enough.
  • Singleton, and the dependency injection that replaced it.
  • Strategy and template method — letting behaviour vary.
  • Adapter, decorator and facade — fitting things together.
  • Observer — telling other parts of the system something happened.

The other seventeen are worth reading about one day. None of them is worth memorising now.

Check your work

What a pattern actually is: a name for a solution you would arrive at anyway, catalogued so people can say one word instead of a paragraph.

Why patterns are noticed rather than planned: the code is written because the problem demanded it; the name comes afterwards.

Why a needless pattern is worse than none: it costs the reader everything a pattern costs and buys them nothing.

The test before using one: what is varying, and is it varying today?

Why waiting is usually right: refactoring to a strategy once you have two real algorithms takes twenty minutes, and the axis you guessed would vary usually is not the one that moves.

Where you have already met them: List.of is a factory, new BufferedReader(new FileReader(...)) is a decorator, every Comparator is a strategy.

What modern Java changed: lambdas shrank strategy and command to one line; records shrank builder for data; singleton became a thing to avoid.

Practice

  1. Find three uses of Comparator in code you have already written in this course. Each is a strategy — say what varies in each.
  2. Open the Javadoc for java.io.InputStream and list five classes that wrap another InputStream. That is the decorator pattern in the standard library.
  3. Take the OperationFactory example above and write down the circumstances in which it would be justified. Be specific.
  4. Look at your capstone's BillingService. Decide what varies in it, and whether any of it is varying today.
  5. Write a Comparator as a full class, then rewrite it as a lambda. Count the lines.
  6. Find one place in your own code where you added flexibility that has never been used. Remove it and see whether anything is worse.
  7. Explain "decorator" to somebody without using the word. Note how long it takes.
  8. List, without looking, the patterns you have used without knowing their name.
  9. Find a pattern in the JDK this lesson did not mention.
  10. Argue the case against teaching patterns to beginners. Then say what you would keep.

Next: making objects, when a constructor is not enough.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship