TypeScript Strategy Pattern Example

1. Definition

The Strategy Design Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. It lets the algorithm vary independently from clients that use it.

2. Problem Statement

Imagine you're building an e-commerce system where you want to integrate multiple payment methods. Using a set of conditional statements for each payment method can lead to code that's hard to maintain, especially when adding or removing payment methods.

3. Solution

The Strategy pattern suggests that you take a class that does something specific in a lot of different ways and extract all these algorithms into separate classes called strategies. The original class, now called context, must have a field for storing a reference to one of the strategies. To switch a processing algorithm, the context replaces the strategy object with another from the family of strategies.

4. Real-World Use Cases

1. Different algorithms for sorting collections.

2. Various payment methods in online stores.

3. Different behaviors for compressing files.

5. Implementation Steps

1. Declare a strategy interface for the varying behavior.

2. Implement a set of concrete strategies that inherit from the strategy interface.

3. Define a context class that uses a strategy.

6. Implementation in TypeScript

// Step 1: Strategy interface
interface PaymentStrategy {
    pay(amount: number): string;
}
// Step 2: Concrete strategies
class CreditCardStrategy implements PaymentStrategy {
    pay(amount: number): string {
        return `Paid ${amount} using credit card.`;
    }
}
class PayPalStrategy implements PaymentStrategy {
    pay(amount: number): string {
        return `Paid ${amount} using PayPal.`;
    }
}
// Step 3: Context class
class ShoppingCart {
    strategy: PaymentStrategy;
    constructor(strategy: PaymentStrategy) {
        this.strategy = strategy;
    }
    checkout(amount: number): void {
        console.log(this.strategy.pay(amount));
    }
}
// Client code
const cart1 = new ShoppingCart(new CreditCardStrategy());
cart1.checkout(100);
const cart2 = new ShoppingCart(new PayPalStrategy());
cart2.checkout(200);

Output:

Paid 100 using credit card.
Paid 200 using PayPal.

Explanation:

The 'ShoppingCart' class (context) uses a payment strategy to process payments. 

There are two concrete payment strategies: 'CreditCardStrategy' and 'PayPalStrategy'. 

Depending on the selected strategy, the 'checkout' method of the 'ShoppingCart' class will use the corresponding payment method. This approach enables flexibility and the easy addition of new payment methods in the future.

7. When to use?

Use the Strategy pattern when:

1. Many related classes only differ in their behavior.

2. You need different variants of an algorithm.

3. An algorithm has a lot of conditional behavior that switches on the data. Extracting strategies as separate classes clean up the code.

4. A class defines many behaviors, and these appear as multiple conditional statements. Instead of many conditionals, move related conditional branches into their own strategy class.


Comments