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
State | Strategy |
---|---|
Different states can be dependent on each other | Strategies 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 vary | Strategy 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