Skip to main content

🧩 Strategy Pattern

✅ Intent

  • Separate behavior based on conditions into individual strategies
  • Allow the strategy to be selected externally for flexible switching

✅ Motivation

  • Branching logic is divided into independent objects, making it easier to test and extend
  • Ideal for systems where algorithm swapping is required

✅ When to Use

  • When algorithms or processing logic need to be dynamically switched
  • When behaviors can be clearly categorized, such as "Pattern A", "Pattern B", etc.

✅ Code Example

// Strategy インターフェース
interface DiscountStrategy {
calculate(basePrice: number): number;
}

// ConcreteStrategy: 学生割引
class StudentDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice * 0.8;
}
}

// ConcreteStrategy: 会員割引
class MemberDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice * 0.9;
}
}

// ConcreteStrategy: VIP割引
class VIPDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice * 0.7;
}
}

// ConcreteStrategy: 割引なし
class NoDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice;
}
}

// Context クラス
class PriceCalculator {
constructor(private discountStrategy: DiscountStrategy) {}

calculatePrice(basePrice: number): number {
return this.discountStrategy.calculate(basePrice);
}
}

// 利用例
const basePrice = 1000;
const studentCalculator = new PriceCalculator(new StudentDiscount());
console.log(studentCalculator.calculatePrice(basePrice)); // 800

const memberCalculator = new PriceCalculator(new MemberDiscount());
console.log(memberCalculator.calculatePrice(basePrice)); // 900

const vipCalculator = new PriceCalculator(new VIPDiscount());
console.log(vipCalculator.calculatePrice(basePrice)); // 700

const regularCalculator = new PriceCalculator(new NoDiscount());
console.log(regularCalculator.calculatePrice(basePrice)); // 1000

✅ Explanation

This code applies the Strategy pattern to enable flexible switching between different discount calculation logics.
The Strategy pattern encapsulates algorithms or logic into separate classes, allowing them to be swapped dynamically.

1. Overview of the Strategy Pattern

  • Strategy: Defines a common interface to treat different algorithms uniformly

    • Represented in this code by DiscountStrategy
  • ConcreteStrategy: Implements the strategy interface and provides specific algorithms

    • Implemented by StudentDiscount, MemberDiscount, VIPDiscount, and NoDiscount in this code
  • Context: Uses a Strategy and switches algorithms dynamically

    • Represented by PriceCalculator in this code

2. Key Classes and Their Roles

  • DiscountStrategy

    • The common interface for discount calculations
    • Defines the method calculate(basePrice: number): number
  • StudentDiscount, MemberDiscount, VIPDiscount, NoDiscount

    • Concrete strategy classes that implement DiscountStrategy
    • Each class applies a different discount rate
  • PriceCalculator

    • The context class
    • Receives a DiscountStrategy instance via its constructor and calculates the final price using the calculatePrice method

3. UML Class Diagram

4. Benefits of the Strategy Pattern

  • Flexibility: New discount logics can be added by simply implementing DiscountStrategy
  • Single Responsibility Principle: Each discount logic is isolated in its own class, improving maintainability
  • Runtime Switching: Different discount strategies can be swapped easily at runtime

This design is highly effective in cases where algorithm switching is needed and significantly improves code extensibility and maintainability.