Design Patterns
Compound Patterns & MVC
Real designs rarely use one pattern in isolation — they combine several to solve a larger problem. Model-View-Controller is the most widely recognized compound pattern: Observer, Strategy, and Composite working together.
- A compound pattern is a combination of two or more patterns applied together to address a recurring higher-level design problem
- MVC decomposes an application into Model (state and business logic), View (presentation), and Controller (translates user input into model changes)
- MVC is Observer (the View observes the Model for changes) + Strategy (the Controller is a swappable strategy for handling input) + Composite (the View is typically a tree of nested UI components)
- The Model has no knowledge of any specific View — multiple Views can observe the same Model simultaneously and stay in sync automatically
- Modern variants (MVP, MVVM, unidirectional-data-flow architectures) are all descendants of the same core idea: separate what changes (state), how it's shown, and how input is handled
| MVC part | Responsibility | Pattern used |
|---|---|---|
| Model | state + business rules; notifies on change | Observer (subject side) |
| View | renders the model; often a nested UI tree | Observer (observer side) + Composite |
| Controller | interprets input, updates the Model | Strategy (swappable input-handling behavior) |
interface ModelListener { void onChange(); }
class TemperatureModel {
private double celsius;
private final List<ModelListener> listeners = new ArrayList<>();
void addListener(ModelListener l) { listeners.add(l); }
void setCelsius(double c) {
this.celsius = c;
listeners.forEach(ModelListener::onChange); // Observer: notify every registered View
}
double getCelsius() { return celsius; }
}
class TemperatureView implements ModelListener {
private final TemperatureModel model;
TemperatureView(TemperatureModel model) { this.model = model; model.addListener(this); }
public void onChange() { System.out.println(model.getCelsius() + "°C"); } // render current state
}
class TemperatureController {
private final TemperatureModel model;
TemperatureController(TemperatureModel model) { this.model = model; }
void userEnteredFahrenheit(double f) { model.setCelsius((f - 32) * 5 / 9); } // input -> Model change
}