OCP Variations: Template Method vs Strategy Pattern
Two Mechanisms for OCP
OCP can be achieved through different design patterns. The two most common are Strategy Pattern (composition-based) and Template Method Pattern (inheritance-based). Both allow extension without modification, but they differ in structure and use cases.
Strategy Pattern (Composition)
Strategy uses composition: the client holds a reference to an interface and delegates to concrete implementations. The client can switch strategies at runtime.
+ performSort(): void
Usage: Sorter can switch from QuickSort to MergeSort at runtime by calling setStrategy(). This is ideal when behavior must change dynamically based on context (data size, user preference, etc.).
Template Method Pattern (Inheritance)
Template Method uses inheritance: an abstract class defines the algorithm structure (template) with fixed and variable steps. Subclasses override specific steps to customize behavior.
// calls steps in order
# brew(): void (abstract)
# pourInCup(): void
# addCondiments(): void (abstract)
# addCondiments()
# addCondiments()
Usage: BeverageMaker.makeBeverage() defines the sequence: boil water, brew, pour, add condiments. Subclasses (TeaMaker, CoffeeMaker) customize brew() and addCondiments() but cannot change the overall flow. This is ideal when the algorithm structure is fixed but specific steps vary.
Comparison and Trade-Offs
| Aspect | Strategy Pattern | Template Method |
|---|---|---|
| Mechanism | Composition (has-a) | Inheritance (is-a) |
| Runtime Flexibility | Can swap strategies dynamically | Behavior fixed at instantiation |
| Coupling | Loose (depends on interface) | Tighter (subclass depends on parent) |
| Use Case | Entire algorithm varies | Algorithm structure fixed, steps vary |
Parking Lot Example: Both Patterns
Strategy Approach: FeeCalculator holds FeeStrategy (hourly, daily, monthly). The entire calculation algorithm changes. You can switch from hourly to monthly billing at runtime.
Template Method Approach: ParkingTicket.calculateFee() defines the flow: get duration, apply base rate, apply discount, add tax. Subclasses (CarTicket, MotorcycleTicket) override getBaseRate() and applyDiscount() but follow the same overall flow. This is appropriate if the calculation steps are standardized but rates vary by vehicle type.
Choosing Between Them: If the calculation process itself differs fundamentally (for example, monthly billing does not care about duration), use Strategy. If all vehicle types follow the same calculation steps but with different parameters, use Template Method. In practice, Strategy is more common in LLD interviews because it offers more flexibility and aligns with composition over inheritance.
Combining Both Patterns
You can use both together. For example, BeverageMaker (Template Method) could use a BrewingStrategy (Strategy) for the brew step. The template controls the overall flow, while strategy allows variation within a specific step. However, this adds complexity; only do this if the domain truly requires both levels of variation.