OBJECT LAB / BEHAVIORAL PATTERN

Strategy Pattern

Encapsulate interchangeable behavior behind one contract, then choose the implementation at runtime.

CompositionOpen/closedRuntime choice
Checkoutamount: $128.00
PaymentContextstrategy: Credit card
Credit cardStrategypay(128.00)
Runtime calls
  1. 1Checkout.pay()
  2. 2PaymentContext.execute()
  3. 3strategy.pay()
  4. 4PaymentResult
Payment stateREADY
01

Problem

Growing conditional branches couple the checkout flow to every payment provider and make change risky.

02

Pattern

The context delegates behavior to a shared strategy interface without knowing provider-specific details.

03

Use carefully

For one stable algorithm, separate strategy objects add indirection without earning meaningful flexibility.

01

Overview

The Strategy pattern defines a family of interchangeable algorithms, puts each one in its own class behind a shared interface, and lets the client choose one at runtime. The code that uses the algorithm (the context) does not know which concrete strategy it holds.

It replaces growing if/else or switch blocks that select behavior by type. Adding a new behavior becomes adding a new class instead of editing tested code, which is the Open-Closed Principle in action.

Choosing how to get to the airport

The goal is fixed: reach the airport. You can take a car, a train, or a taxi. You choose based on budget and time, and the rest of your trip plan does not change. Each option is a strategy.

02

When to use it

  • You have several ways to do the same task: payment methods, pricing rules, sorting, compression, routing.
  • A method contains a switch on a type flag that keeps growing.
  • Behavior must be chosen or swapped at runtime based on configuration or user input.
  • You want to test each algorithm in isolation.
03

Where it shows up in interviews

Interchangeable algorithms

Recognize it when: several ways to do the same task, chosen at runtime.

  • Design a payment system
  • Design a parking fee calculator
  • Design a discount engine
Replace growing switch

Recognize it when: switch on type keeps getting new cases.

  • Refactor shipping cost calculation
  • Design Splitwise split types
04

Where it is used in real software

java.util.Comparator

Sorting takes a comparison strategy: Collections.sort(list, comparator).

Passport.js

Authentication strategies (local, Google, GitHub) plug into the same login flow.

Spring Security

PasswordEncoder implementations (bcrypt, argon2) are swappable strategies.

05

Key terms

Strategy interface
The shared contract, for example PaymentStrategy.pay(amount).
Concrete strategy
One implementation, such as CardPayment or UpiPayment.
Context
The class that holds a strategy reference and delegates to it, such as Checkout.
Composition
The context has a strategy rather than inheriting behavior.
06

How to apply it

  1. 1
    Find the varying behavior

    Identify the switch or if/else chain that selects an algorithm.

  2. 2
    Define the interface

    Extract one method signature that every variant can implement.

  3. 3
    Move each branch into a class

    Each case becomes a concrete strategy with its own dependencies and tests.

  4. 4
    Inject the strategy

    Pass the strategy into the context through its constructor or a setter.

  5. 5
    Select at the edge

    A factory or map chooses the strategy from input, keeping selection logic in one place.

07

Before and after

A checkout that supports card, UPI, and wallet payments

Step 1 / 4
ConcernWithout StrategyWith Strategy
Adding PayPalEdit Checkout's switch statementAdd a PayPalPayment class
TestingTest every branch through CheckoutTest each strategy alone
Checkout knowsEvery provider's API detailsOnly PaymentStrategy.pay()
Risk of changeCan break existing methodsExisting classes untouched

NOWConcern: Adding PayPal | Without Strategy: Edit Checkout's switch statement | With Strategy: Add a PayPalPayment class

The context depends on an abstraction, and new behavior is added by extension. Selection still happens somewhere, but in one small factory instead of inside business logic.

08

Implementation

interface PaymentStrategy {  pay(amount: number): PaymentResult;} type PaymentResult = { success: boolean; fee: number; reference: string }; class CardPayment implements PaymentStrategy {  constructor(private cardNumber: string) {}  pay(amount: number): PaymentResult {    const fee = amount * 0.029;    return { success: true, fee, reference: `CARD-${this.cardNumber.slice(-4)}` };  }} class UpiPayment implements PaymentStrategy {  constructor(private upiId: string) {}  pay(amount: number): PaymentResult {    return { success: true, fee: 0, reference: `UPI-${this.upiId}` };  }} class Checkout {  constructor(private strategy: PaymentStrategy) {}   setStrategy(strategy: PaymentStrategy) {    this.strategy = strategy; // swap at runtime  }   complete(amount: number): PaymentResult {    return this.strategy.pay(amount); // no idea which provider  }} const checkout = new Checkout(new CardPayment("4111111111111111"));checkout.complete(128);checkout.setStrategy(new UpiPayment("user@bank"));checkout.complete(128);
09

Complexity and performance

Runtime cost1 indirect call

Negligible compared with the work the strategy performs.

Classes added1 per variant

Plus one interface.

10

Trade-offs

More classes

For two stable variants, a simple if statement is clearer. Use Strategy when variants are growing or tested separately.

Clients must choose

Someone still selects the strategy. Keep that in a factory or registry rather than scattering it.

Functions can be strategies

In TypeScript, Python, or Java 8+, a function type or lambda can replace a class when the strategy has no state.

11

Variants and related techniques

Strategy vs State

Both delegate to an interface. In Strategy, the client picks the behavior; in State, the object switches its own behavior as its state changes.

Strategy vs Template Method

Template Method varies steps through inheritance; Strategy varies the whole algorithm through composition.

Strategy registry

A Map<string, Strategy> lets configuration or plugins add strategies without modifying code.

12

Common mistakes

  • Strategies that need different parameters.

    Fix: Pass a shared context object or supply extra data through the strategy's constructor.

  • Moving the switch into the context's constructor.

    Fix: Keep selection in a factory so the context stays closed to modification.

  • Creating a strategy for a single algorithm.

    Fix: Wait until a second real variant exists (YAGNI).

13

Interview questions

How does Strategy support the Open-Closed Principle?

New behavior is added as a new class implementing the interface. The context and existing strategies are not modified.

What is the difference between Strategy and State?

Intent and who switches. Strategy is chosen externally for how to do something; State represents what mode the object is in and transitions internally.

14

Practice problems

ProblemDifficultyWhat it trains
Discount engineEasyPercentage, flat, and buy-one-get-one strategies.
Parking fee calculatorMediumHourly, daily, and weekend pricing.
Pluggable compression toolMediumRegistry of zip, gzip, and none.