Strategy Design Pattern

What is the strategy design pattern?

The strategy design pattern best suits when multiple strategies (algorithms) are available for a task. The consumer decides the strategy at runtime.

The strategy design pattern is one of the behavioral design patterns.

Advantages of strategy design pattern:

  • We can change strategies used inside an object at runtime.
  • We can isolate the implementation details from the code that uses it.
  • We can replace inheritance with composition.
  • Encourages Open/Closed Principle. We can introduce new strategies without having to change the context.
  • Code is easier to maintain as modifying or understanding strategy does not require you to understand the whole main object
  • The Strategy pattern promotes loose coupling by separating the algorithms from the client code.
  • Using the Strategy pattern may improve readability because a class that implements some particular strategy typically should have a descriptive name

Disadvantages of strategy design pattern:

  • If we have a couple of algorithms and they rarely change, there’s no real reason to use a strategy design pattern.
  • There are cases where the strategy pattern is an overkill
  • A lot of modern programming languages have functional type support that lets you implement different versions of an algorithm inside a set of anonymous functions. Then we could use these functions without bloating your code with extra classes and interfaces.

Usage of strategy design pattern::

  • File Compression: Different compression algorithms can be implemented as strategies to compress and decompress files.
  • Sorting Algorithms: Different sorting algorithms, such as quicksort and merge sort, can be implemented as strategies to sort data.
  • Payment Gateways: Different payment gateways, such as PayPal and Stripe, can be implemented as strategies to process online payments.
  • UI Rendering Engines: Different UI rendering engines, such as Canvas and WebGL, can be implemented as strategies to render graphical interfaces.

Difference between Strategy and State design pattern

StateStrategy
Different states can be dependent on each otherStrategies are independent and not aware of each other
The state design pattern is about doing different things based on the state, hence the result may varyStrategy design pattern is about having different implementations that accomplish the same thing

Example of strategy design pattern:

// client.ts
import PaymentService from './PaymentService'
import PaymentByCreditCard from './strategy/PaymentByCreditCard'
import PaymentByPayPal from './strategy/PaymentByPayPal'


const paymentService = new PaymentService();
paymentService.setStrategy(new PaymentByCreditCard());
paymentService.processOrder(100);

console.log("==========================================");

paymentService.setStrategy(new PaymentByPayPal());
paymentService.processOrder(100);


// PaymentStrategy.ts
export default interface PaymentStrategy {

    collectPaymentDetails(): void;

    validatePaymentDetails(): boolean;

    pay(amount: number): void;

}


// PaymentService.ts
import PaymentStrategy from './strategy/PaymentStrategy'
export default class PaymentService {

    private cost: number;
    private includeDelivery = true;

    strategy: PaymentStrategy;

    setStrategy (specificStrategy: PaymentStrategy): void {
        this.strategy = specificStrategy;
    }

    public processOrder(cost: number) :void {
        this.cost = cost;
        this.strategy.collectPaymentDetails();
        if (this.strategy.validatePaymentDetails()) {
            this.strategy.pay(this.getTotal());
        }
    }

    private getTotal(): number {
        return this.includeDelivery ? this.cost + 10 : this.cost;
    }

}


// PaymentByCreditCard.ts
import PaymentStrategy from './PaymentStrategy'

export default class PaymentByCreditCard implements PaymentStrategy {

    public collectPaymentDetails(): void {
        // Pop-up to collect card details...
        console.log("Collecting Card Details...");
    }

    public validatePaymentDetails(): boolean {
        // Validate credit card...
        console.log("Validating Card Info: ");
        return true;
    }

    public pay(amount: number): void {
        console.log("Paying " + amount + " using Credit Card");
    }

}



// PaymentByPayPal.ts
import PaymentStrategy from './PaymentStrategy'

export default class PaymentByPayPal implements PaymentStrategy {

    private email: string;
    private password: string;

    public collectPaymentDetails(): void {
        // Pop-up to collect PayPal account details
        console.log("Collecting PayPal Account Details...");
    }

    public validatePaymentDetails(): boolean {
        // Validate account...
        console.log("Validating PayPal Information");
        return true;
    }

    public pay(amount: number): void {
        console.log("Paying " + amount + " using PayPal");
    }

}


Run the above strategy code

Collecting Card Details...
Validating Card Info: 
Paying 110 using Credit Card
==========================================
Collecting PayPal Account Details...
Validating PayPal Information
Paying 110 using PayPal

Source code: Github link

Reference