Strategy Pattern Guide: How Do You Change Behavior Without Growing Conditionals?
Dev

Strategy Pattern Guide: How Do You Change Behavior Without Growing Conditionals?


In real code, the same kind of task often needs different behavior depending on the situation. When those differences start growing inside one large if/else block, the structure can become messy very quickly. The strategy pattern is one of the classic ways to address that.

In this post, we will cover:

  • what the strategy pattern is
  • why it helps reduce branching
  • when it fits well
  • how it connects to object-oriented design principles

The key idea is that the strategy pattern separates “what to do” from “how to do it,” so behavior can be swapped more cleanly.

What is the strategy pattern?

The strategy pattern represents one kind of behavior with multiple interchangeable implementations.

For example:

  • card payment strategy
  • bank transfer strategy
  • points payment strategy

Each one fulfills the same general role in a different way.

Why does it help reduce conditionals?

If every new variation expands one large service with more if/else branches:

  • the code becomes harder to read
  • testing becomes harder
  • adding new behavior touches old code repeatedly

The strategy pattern separates each behavior into its own object so that branching does not keep spreading through the same place.

When does it fit well?

  • when behavior variants keep growing
  • when the same role has multiple implementations
  • when behavior may change at runtime

So it fits especially well when behavior replacement is a real concern.

How does it connect to object-oriented principles?

The strategy pattern often lines up naturally with:

  • OCP: new strategies can be added with less modification to stable code
  • DIP: code can depend on an abstract role instead of a concrete strategy
  • polymorphism: different implementations can stay behind the same message

So the strategy pattern is a very practical example of object-oriented principles becoming concrete structure.

Common misunderstandings

1. Every if/else should become a strategy pattern

Not always. For very small and stable variations, that may be excessive.

2. The strategy pattern only increases class count

It can increase object count, but for frequently changing behavior it often reduces long-term change cost.

3. It is mainly an inheritance pattern

In practice, it is often built more naturally with composition and interfaces.

Simple Example

interface PaymentStrategy {
  pay(amount: number): void;
}

class CardPayment implements PaymentStrategy {
  pay(amount: number) {
    console.log(`Pay ${amount} with card`);
  }
}

class PointsPayment implements PaymentStrategy {
  pay(amount: number) {
    console.log(`Pay ${amount} with points`);
  }
}

class CheckoutService {
  constructor(private strategy: PaymentStrategy) {}

  checkout(amount: number) {
    this.strategy.pay(amount);
  }
}

const service = new CheckoutService(new CardPayment());
service.checkout(100);

The key point is that CheckoutService depends on PaymentStrategy, not on one concrete payment implementation.

FAQ

Q. Where should beginners try strategy first?

Payment methods, discount rules, sorting behavior, and notification channels are common good examples.

Q. Is strategy pattern the same as polymorphism?

Not exactly, but it is a classic structure that uses polymorphism.

Q. Who chooses the strategy?

Usually a higher-level context or composition layer selects and injects the strategy object.

Start Here

Continue with the core guides that pull steady search traffic.