← Back to Home
Strategy Pattern
Define a family of algorithms, encapsulate each one, and make them interchangeable without breaking existing code.
What is it?
The Strategy pattern allows you to select algorithms at runtime without modifying client code or creating complex conditional logic that breaks when extended.
Interactive Demo: Strategy vs Hardcoded Logic
Test a discount system. Watch what happens when a NEW discount type (Flash Sale) is needed:
Shopping Scenario:
📦 Purchase Amount: $100
🎓 VIP Membership: 3 years
⏰ Flash Sale Time Left: 2 hours
⚡ Strategy Pattern
Activity Log:
Try the discount buttons above...
🔀 Hardcoded Logic
Activity Log:
Try the buttons above...
💡 Key Insight:
- • Strategy Pattern: NEW Flash Sale works immediately - no code changes needed!
- • Hardcoded Logic: NEW Flash Sale CRASHES - missing switch case breaks production!
- • Real Impact: Strategy enables safe extension, hardcoded logic creates maintenance nightmares
Code Example
interface DiscountStrategy { calculate(amount: number, details?: any): number; getName(): string; } class FlashSaleDiscount implements DiscountStrategy { calculate(amount: number, details: { hoursLeft: number }): number { if (details.hoursLeft <= 1) return amount * 0.50; // 50% off if (details.hoursLeft <= 6) return amount * 0.35; // 35% off return amount * 0.25; // 25% off } getName(): string { return "Flash Sale"; } } class DiscountCalculator { private strategy: DiscountStrategy; setStrategy(strategy: DiscountStrategy) { this.strategy = strategy; // Clean algorithm switching } calculate(amount: number, details?: any): number { return this.strategy.calculate(amount, details); // No conditionals! } } // Usage - New strategies work immediately const calculator = new DiscountCalculator(); calculator.setStrategy(new FlashSaleDiscount()); const discount = calculator.calculate(100, { hoursLeft: 2 }); // vs Hardcoded Approach - Breaks when extended class HardcodedCalculator { static calculate(amount: number, type: string, details?: any): number { switch (type) { // This switch must be updated everywhere! case "student": return amount * 0.15; case "senior": return amount * 0.20; case "vip": return amount * 0.25; // Missing "flash" case = Runtime Error! default: throw new Error(`Unknown type: ${type}`); } } }
Common Uses
- Payment processing (credit card, PayPal, crypto, buy-now-pay-later)
- Pricing strategies (regular, discount, subscription, bulk pricing)
- Data validation (email, phone, password strength, custom rules)
- File export formats (PDF, Excel, CSV, JSON)
- Authentication methods (OAuth, JWT, API keys, biometric)
- Sorting/filtering algorithms (performance vs memory trade-offs)
When to Use
- When you need multiple ways to perform the same task
- When algorithms should be interchangeable at runtime
- To eliminate complex if/else or switch statement chains
- When new algorithm variants are frequently added
- When algorithms have different performance characteristics
Caution
- Increases the number of classes (but improves maintainability)
- Clients must understand available strategies
- Overkill for simple algorithms that never change
- Strategy selection logic still needs to exist somewhere