Bird
Raised Fist0

Strategy Pattern - Pluggable Algorithms and Runtime Behavior Swap

LLDeasyInterview freq: high
Choose your preparation mode4 modes available
🏗️
Strategy Pattern - Pluggable Algorithms and Runtime Behavior Swap
Enable runtime swapping of algorithms by encapsulating them in separate classes and delegating behavior.
easyDesign Patterns - AppliedFreq: high
Prerequisites:OOP BasicsPolymorphism
⚙️
Functional Requirements
  • Define a common interface or abstract class for all strategies.
  • Context class holds a reference to a strategy and delegates calls.
  • Allow runtime replacement of the strategy instance in Context.
  • Ensure thread-safe access and modification of the strategy reference.
  • Support multiple concrete strategy implementations with different algorithms.
  • Prevent client code from depending on concrete strategy implementations.
  • Provide clear extension points for adding new strategies.
👤
Use Cases
  • Client sets a specific algorithm implementation at runtime.
  • Context delegates algorithm execution to the current strategy.
  • Client swaps strategy dynamically during execution.
  • System supports adding new strategies without modifying existing code.
  • Ensure thread-safe strategy swapping in concurrent environments.
🧑‍💻
Actors
  • Client
  • Strategy
  • Context
❓
Clarifying Questions to Ask
  • How many concurrent threads will access or modify the strategy in Context?
  • Should strategy swapping be atomic and visible immediately to all threads?
  • Are there any performance constraints on strategy invocation?
  • Is there a need for fallback or default strategies?
  • How should errors in strategy execution be handled?
  • Are strategies stateless or do they maintain internal state?
  • Should strategies be singleton instances or created per use?
Out of Scope
✗ Persistence of strategies or context state.
✗ Distributed system synchronization of strategies.
✗ UI or frontend integration.
⚡
QPS Calculation
read qps1000
write qps100
🖥️
Server Estimate
3
🔢
Enumerations
enum StrategyType
ALGORITHM_A | ALGORITHM_B | ALGORITHM_C
Defines distinct strategy identifiers to prevent typo bugs and enable exhaustive switch statements when selecting strategies.
enum ExecutionStatus
SUCCESS | FAILURE | IN_PROGRESS
Represents the result of executing a strategy, enabling clear status handling and avoiding magic strings.
📦
Strategy
1 fields
none (interface defines behavior only)
Declare the algorithm interface that all concrete strategies must implement.
Why thisInterface allows multiple implementations and supports polymorphism in Java.
Why notAbstract classes limit multiple inheritance and add unnecessary state.
public ExecutionStatus execute(ContextData data)Defines the contract for executing the algorithm with given context data.
📦
ConcreteStrategyA
1 fields
none (stateless)
Implements algorithm A following the Strategy interface.
Why thisSeparate class encapsulates algorithm A for modularity and runtime swapping.
Why notEmbedding logic in Context reduces flexibility and violates OCP.
public ExecutionStatus execute(ContextData data)Executes algorithm A logic.
📦
ConcreteStrategyB
1 fields
none (stateless)
Implements algorithm B following the Strategy interface.
Why thisSeparate class encapsulates algorithm B for modularity and runtime swapping.
Why notEmbedding logic in Context reduces flexibility and violates OCP.
public ExecutionStatus execute(ContextData data)Executes algorithm B logic.
📦
Context
1 fields
private volatile Strategy currentStrategy
Maintains a reference to a Strategy and delegates execution to it. Allows runtime swapping of the strategy in a thread-safe manner.
Why thisHolds volatile reference for visibility and synchronized setter for atomic updates.
Why notUsing non-volatile or unsynchronized references risks stale or inconsistent state.
public synchronized void setStrategy(Strategy strategy)Atomically sets the current strategy to the provided instance.
public ExecutionStatus executeStrategy(ContextData data)Delegates execution to the current strategy instance.
📦
ContextData
1 fields
private Map<String, Object> parameters
Encapsulates input data required by strategies for execution.
Why thisFlexible key-value map supports extensible parameters for different strategies.
Why notFixed parameter classes reduce flexibility and increase coupling.
public Object getParameter(String key)Retrieves a parameter value by key.
public void setParameter(String key, Object value)Sets a parameter value by key.
🔗
Relationships
Context◇──►Strategy[1]
aggregationStrategy can exist independently of Context; Context holds a reference to Strategy.
ConcreteStrategyA──►Strategy[1]
realizationConcreteStrategyA implements Strategy interface; lifecycle independent.
ConcreteStrategyB──►Strategy[1]
realizationConcreteStrategyB implements Strategy interface; lifecycle independent.
Context──►ContextData[1]
associationContextData passed as parameter; Context does not own lifecycle.
🗄️
Strategies
PK: strategy_id
strategy_id UUIDstrategy_type TEXTimplementation_class TEXTcreated_at TIMESTAMP
Stores metadata about available strategies.
🗄️
ExecutionLogs
PK: execution_id
execution_id UUIDstrategy_id UUIDstatus TEXTtimestamp TIMESTAMPdetails TEXT
Logs execution results of strategies.
🔌
POST
SetStrategy
Request
{
  "strategyType": "StrategyType enum"
}
Response
{
  "status": "success or failure message"
}
Allows client to set or swap the current strategy at runtime.
🔌
POST
ExecuteStrategy
Request
{
  "parameters": "Map<String, Object>"
}
Response
{
  "executionStatus": "ExecutionStatus enum"
}
Triggers execution of the current strategy with given parameters.
🔌
GET
GetCurrentStrategy
Request
{}
Response
{
  "strategyType": "StrategyType enum"
}
Returns the currently active strategy type.

Practice

(1/5)
1. In the Restaurant Management System, the TableManager class has a method reserveTable() that checks if a table is available and then marks it reserved. Without synchronizing reserveTable(), which exact sequence of thread interleaving causes double-booking?
medium
A. Thread 1 and Thread 2 both wait on a lock, preventing any reservation.
B. Thread 1 and Thread 2 both call reserveTable() simultaneously and both fail to reserve.
C. Thread 1 reserves a table, then Thread 2 cancels it immediately after.
D. Thread 1 checks isAvailable() -> true, context switch; Thread 2 checks isAvailable() -> true; both reserve the same table.

Solution

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

    Without synchronization, Thread 1 reads table as available but before reserving, Thread 2 also reads it as available.
  2. Step 2: Both threads proceed to reserve the same table

    Because the reservation step is not atomic, both threads mark the table reserved, causing double-booking.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Check-then-act without lock -> double-booking [check]
Hint: Check-then-act gap -> double-booking race [check]
Common Mistakes:
2. The auction system currently calculates fees with a fixed strategy. To add a WeekendFeeStrategy without modifying existing classes, which SOLID principle is being applied and what is the minimum required change?
medium
A. Open/Closed Principle: create a new WeekendFeeStrategy class implementing FeeStrategy; inject it without changing existing code.
B. Liskov Substitution Principle: subclass Auction to WeekendAuction overriding fee calculation.
C. Single Responsibility Principle: modify Auction class to handle weekend fees directly.
D. Dependency Inversion Principle: hardcode weekend fee logic inside FeeStrategy implementation.

Solution

  1. Step 1: Identify SOLID principle

    Open/Closed Principle (OCP) states software entities should be open for extension but closed for modification.
  2. Step 2: Apply OCP by adding WeekendFeeStrategy implementing FeeStrategy interface without modifying existing classes.

  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class + injection -> OCP compliance [check]
Hint: Add new strategy class, no existing code change -> OCP [check]
Common Mistakes:
3. You want to add a WeekendFeeStrategy to the parking lot pricing system. Which minimum change respects SOLID principles?
medium
A. Add a boolean flag isWeekend to Vehicle and adjust pricing accordingly.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing classes.
C. Modify the existing FeeCalculator class to add weekend logic inside.
D. Create a subclass WeekendFeeCalculator extending FeeCalculator and override methods.

Solution

  1. Step 1: Identify SOLID principle involved

    Open-Closed Principle (OCP) requires adding new functionality without modifying existing code.
  2. Step 2: Evaluate options

    Modify the existing FeeCalculator class to add weekend logic inside. violates OCP by modifying existing class. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing classes. respects OCP by adding new strategy class. Add a boolean flag isWeekend to Vehicle and adjust pricing accordingly. incorrectly mixes state into Vehicle, violating SRP. Create a subclass WeekendFeeCalculator extending FeeCalculator and override methods. adds subclass but may cause class explosion and tight coupling.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class + no existing class change -> OCP respected [check]
Hint: Add new strategy class, avoid modifying existing code [check]
Common Mistakes:
4. You want to add a WeekendFeeStrategy to calculate weekend parking fees without modifying existing classes. Which SOLID principle guides the minimum change, and what is the correct approach?
medium
A. Modify the ParkingLot class to add weekend fee logic, enforcing Single Responsibility Principle.
B. Add weekend fee logic inside existing FeeStrategy implementations, following Dependency Inversion Principle.
C. Create a WeekendFeeStrategy subclass of ParkingLot to override fee calculation, following Liskov Substitution Principle.
D. Create a new WeekendFeeStrategy class implementing FeeStrategy interface, and inject it where needed, following Open/Closed Principle.

Solution

  1. Step 1: Identify the SOLID principle for extensibility

    Open/Closed Principle (OCP) requires adding new functionality without modifying existing code.
  2. Step 2: Evaluate approaches

    Creating a new FeeStrategy implementation and injecting it respects OCP and DIP; modifying ParkingLot or existing strategies violates OCP or mixes responsibilities.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New FeeStrategy class + injection -> OCP and DIP respected [check]
Hint: New strategy class + injection -> Open/Closed Principle [check]
Common Mistakes:
5. In a parking lot system, if parkVehicle() is not synchronized, which exact sequence of Thread 1 and Thread 2 causes double-booking of the same spot?
medium
A. Thread 1 parks vehicle, Thread 2 waits until Thread 1 finishes, then parks another vehicle.
B. Thread 1 and Thread 2 both crash due to simultaneous access.
C. Thread 1 checks spot availability -> true, context switch; Thread 2 checks spot availability -> true; both park simultaneously.
D. Thread 1 parks vehicle, Thread 2 reads spot as occupied and waits.

Solution

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

    Without synchronization, Thread 1 reads spot as available but before marking it occupied, context switches to Thread 2 which also reads it as available.
  2. Step 2: Both threads proceed to park, causing double-booking

    Because the state update is not atomic, both threads park vehicles in the same spot simultaneously.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Unsynchronized check-then-act -> double-booking race [check]
Hint: Check-then-act gap causes double-booking without synchronization [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