Bird
Raised Fist0

Strategy Pattern - Pluggable Algorithms and Runtime Behavior Swap

LLDeasyInterview freq: high
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
Strategy interface

Strategy is a Java interface defining the execute() method without state.

🎯 Tests whether candidate knows interfaces cannot hold instance state in Java, enabling OCP by allowing new strategies without modifying existing code.
public interface Strategy {
    void execute();
}
ConcreteStrategyA realization

ConcreteStrategyA implements Strategy interface providing specific execute() behavior.

🎯 Tests understanding of realization relationship and how polymorphism enables runtime behavior swap without changing Context.
public class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("Executing Strategy A");
    }
}
Context composition with ContextData

Context composes ContextData, owning its lifecycle, and holds a reference to Strategy for delegation.

🎯 Tests whether candidate distinguishes composition (ContextData lifecycle bound to Context) from association (Strategy lifecycle independent).
public class Context {
    private Strategy strategy;
    private final ContextData data = new ContextData();

    public synchronized void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void executeStrategy() {
        strategy.execute();
    }
}
ContextData encapsulated state

ContextData holds mutable state accessed and modified by Context, encapsulating data separate from behavior.

🎯 Tests understanding of separating state (ContextData) from behavior (Strategy) and lifecycle ownership via composition.
public class ContextData {
    private String state;
    public String getState() { return state; }
    public void setState(String state) { this.state = state; }
}
📐
Class Diagram
Class Diagram
       +----------------+
       | <<Interface>>  |
       |   Strategy     |
       +----------------+
       | +execute():void|
       +----------------+
              ^
              |  realization
       +--------------------+
       | ConcreteStrategyA   |
       +--------------------+
       | +execute(): void    |
       +--------------------+
              ^
              |  realization
       +--------------------+
       | ConcreteStrategyB   |
       +--------------------+
       | +execute(): void    |
       +--------------------+
       
       +----------------+
       | Context        |
       +----------------+
       | -strategy:Strategy  |
       | -data: ContextData  |
       +----------------+
       | +setStrategy(Strategy):void [sync] |
       | +executeStrategy():void             |
       +----------------+
              ◆ composition
              |
       +----------------+
       | ContextData    |
       +----------------+
       | -state: String |
       +----------------+
       | +getState():String |
       | +setState(String):void |
       +----------------+

This diagram illustrates the Strategy pattern in Java focusing on pluggable algorithms and runtime behavior swap. The Strategy interface is a pure interface without state, enforcing the Open-Closed Principle by allowing new strategies without modifying existing code. ConcreteStrategyA and ConcreteStrategyB realize this interface, enabling polymorphic behavior. Context composes ContextData, owning its lifecycle, which encapsulates mutable state separate from behavior. Context holds a reference to Strategy via association, allowing runtime swapping of algorithms. The setStrategy method is synchronized to ensure thread-safe updates of the strategy reference. This design cleanly separates concerns, leverages Java interface realization, composition lifecycle, and enforces SOLID principles for extensibility and maintainability.

Primary Focus

✓ Inheritance vs Realization + Composition lifecycle + Strategy OCP + Abstract class state

Practice

(1/5)
1. In a Music Streaming Library design, a Playlist class has a private constructor and a static synchronized getInstance() method that returns the single instance. Which design pattern is applied here and why is it the correct choice?
easy
A. Factory pattern, because it controls object creation centrally.
B. Builder pattern, to construct complex Playlist objects step-by-step.
C. Prototype pattern, to clone existing Playlist instances efficiently.
D. Singleton pattern, to ensure only one Playlist instance manages the playback queue globally.

Solution

  1. Step 1: Identify the pattern from private constructor and static synchronized getInstance()

    This is the Singleton pattern, which restricts instantiation to one object and provides a global access point.
  2. Step 2: Why Singleton fits Playlist playback queue management

    Since the playback queue must be globally consistent and unique per user session, Singleton ensures only one instance manages it, avoiding conflicting states.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static getInstance() = Singleton [check]
Common Mistakes:
2. A ParkingLot class has a private constructor and a static synchronized getInstance() method returning the single instance. Which design pattern is applied here and why is this the correct use case?
easy
A. Prototype pattern, to clone ParkingLot instances efficiently.
B. Factory pattern, because it controls object creation centrally.
C. Builder pattern, to construct complex ParkingLot objects step-by-step.
D. Singleton pattern, to ensure only one ParkingLot instance manages all spots.

Solution

  1. Step 1: Identify the pattern from constructor and method

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single instance is created and accessed globally.
  2. Step 2: Why Singleton fits ParkingLot

    ParkingLot must be unique to coordinate spot allocation and pricing consistently across the system, so Singleton enforces this single shared instance.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized static getInstance() -> Singleton pattern [check]
Hint: Private constructor + static getInstance() = Singleton [check]
Common Mistakes:
3. Consider a tryConsume() method in TokenBucketRateLimiter that checks if tokens are available and then decrements the count without synchronization. Which exact thread interleaving causes double token consumption?
medium
A. Thread 1 reads tokens=1, decrements; Thread 2 waits until Thread 1 finishes
B. Thread 1 increments tokens while Thread 2 decrements tokens simultaneously
C. Thread 1 and Thread 2 both block on synchronized method, then proceed sequentially
D. Thread 1 checks tokens > 0 -> true, context switch; Thread 2 checks tokens > 0 -> true; both decrement tokens

Solution

  1. Step 1: Identify check-then-act race condition

    Without synchronization, both threads can read tokens > 0 before either decrements.
  2. Step 2: Trace exact interleaving causing double consumption

    Thread 1 checks tokens > 0 -> true, context switch; Thread 2 checks tokens > 0 -> true; both proceed to decrement, consuming same token twice.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Unsynchronized check-then-act allows double token consumption [check]
Hint: Check tokens > 0 twice before decrement -> double consume [check]
Common Mistakes:
4. The ESPNcricinfo system needs to support ElectricCar vehicles that require ChargingSpot parking spots. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Modify Vehicle class to add isElectric flag and add charging logic inside existing Spot classes.
B. Create a new ElectricCar class and ChargingSpot class, then modify ParkingLot to handle both types explicitly.
C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar extends Vehicle, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
D. Add a new method in Vehicle interface for charging and implement it only in ElectricCar.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and new subclasses allows extension without changing existing class code.
  2. Step 2: Update compatibility map for new types

    Updating SpotCompatibility.COMPATIBILITY_MAP supports new vehicle-spot matching without altering existing logic.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Extend enums + new subclasses + update compatibility map -> no existing class changes [check]
Hint: Extend enums + new subclasses + compatibility map -> minimal change [check]
Common Mistakes:
5. To add ElectricCar needing ChargingSpot compatibility, what is the minimum change to the current design without modifying existing classes?
hard
A. Create a new ElectricParkingLot subclass handling charging spots, duplicating logic
B. Modify Vehicle class to add electric-specific fields and methods, breaking OCP
C. Add ELECTRIC_CAR to VehicleType, CHARGING to SpotType, create ElectricCar extending Vehicle, and update SpotCompatibility.COMPATIBILITY_MAP
D. Add a boolean isElectric flag to Vehicle and add conditional logic in ParkingLot

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new vehicle and spot types via enums and creating a new subclass ElectricCar extends functionality without changing existing code.
  2. Step 2: Update compatibility map externally

    Updating SpotCompatibility.COMPATIBILITY_MAP to include new mappings allows the system to recognize charging spots without modifying core logic.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    New enums + subclass + compatibility map update -> minimal change, OCP preserved [check]
Hint: New enums + subclass + map update -> extend without modify [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard