DEV Community

Cover image for Design Patterns Simplified: Part 2 – Strategy Pattern (a.k.a. “Pick Your Coupon Wisely”)
Prateek Prabhakar
Prateek Prabhakar

Posted on • Edited on • Originally published at Medium

Design Patterns Simplified: Part 2 – Strategy Pattern (a.k.a. “Pick Your Coupon Wisely”)

Strategy Pattern belongs to the Behavioral category of design patterns.
Why? Because it’s all about how objects interact and behave. Strategy focuses on choosing behavior dynamically at runtime, like swapping brains for specific tasks.

In today’s fast paced world of e-commerce and quick-commerce, you’ve likely had that classic cart checkout moment, staring at a bunch of coupon codes, trying to pick the one that saves you the most money.
If yes, congratulations! You’ve already seen the Strategy Pattern in real life.


The Shopping Cart Coupon Chaos

Let’s say you’re building your very own e-commerce app and want to support multiple coupon types,

"FLAT200" → ₹200 off
"NEWUSER" → 20% off
"FESTIVE" → ₹100 + free delivery
"BUYMORE" → 15% off above ₹1000

Your code might start like this,

Function ApplyCoupon(cartAmount, couponCode)
    If couponCode == "FLAT200"
        Return cartAmount - 200
    Else if couponCode == "NEWUSER"
        Return cartAmount * 0.8
    Else if couponCode == "FESTIVE" 
        Return cartAmount - 100  // free delivery handled elsewhere
    Else if couponCode == "BUYMORE" AND cartAmount > 1000
        Return cartAmount * 0.85
    Else
        Return cartAmount
Enter fullscreen mode Exit fullscreen mode

This works. Until, we encounter some challenges/bottlenecks like,

  • 2 more coupons get added next week
  • You need to test different coupon logics
  • Marketing decides to change all rules before the sale ends
  • Someone adds one else if with a wrong condition and there is a disaster

Enter the Strategy Pattern

It’s like hiring a dedicated coupon brain for each discount logic.

You separate the behavior (how to apply discount) from the decision (which one to use). This is now definitely clean, pluggable and testable.

What does the code look like?

// Step 1: Define Strategy Interface
Interface DiscountStrategy
    Method Apply(cart)

// Step 2: Implement each strategy
Class PercentageDiscountStrategy Implements DiscountStrategy
    Method Apply(cart)
        Return cart.total * 0.9   // 10% off

Class FreeShippingStrategy Implements DiscountStrategy
    Method Apply(cart)
        Return cart.total - cart.shippingFee

Class FlatDiscountStrategy Implements DiscountStrategy
    Method Apply(cart)
        Return cart.total - 100

// Mix it up with a Factory pattern 😎
// Step 3: Strategy Factory
Class DiscountStrategyFactory
    Static Method GetStrategy(couponCode)
        strategyName = DB.GetStrategyClassFor(couponCode)

        If strategyName == "PercentageDiscountStrategy"
            Return new PercentageDiscountStrategy()
        Else if strategyName == "FreeShippingStrategy"
            Return new FreeShippingStrategy()
        Else if strategyName == "FlatDiscountStrategy"
            Return new FlatDiscountStrategy()
        Else
            Return new NoDiscountStrategy()

// caller logic
Function ApplyCoupon(cart, couponCode)
    strategy = DiscountStrategyFactory.GetStrategy(couponCode)
    finalAmount = strategy.Apply(cart)
    Return finalAmount
Enter fullscreen mode Exit fullscreen mode

Did you notice something familiar in the code?
We’re using a Factory Pattern to decide which discount strategy to use, based on some configuration stored in DB or elsewhere. With this, we get rid of the messy if-else branching scattered across the main logic. It is now one centralized place that handles object creation based on input. This is one way of combining multiple design patterns together to make the actual business logic stay clean and decoupled.

💡 If you're not sure what Factory Pattern is or how it works, check out Part 1 of this series.

Why Use Strategy Pattern?

  • Business logic keeps changing
  • No more branching in core code
  • Plug-and-play behavior at runtime
  • Add new rules without touching old ones (Open-Closed Principle)
  • Easily unit test each discount logic separately

Use Cases?

  • Coupon logic
  • Payment gateways
  • Sorting algorithms
  • UI themes
  • Game player behavior
  • Pricing strategies
  • Tax calculation logic

To summarize, it would be apt to say,

Strategy Pattern is a design pattern that lets you define a family of algorithms (strategies), encapsulate them in separate classes, and switch them at runtime.
Code stays clean, changes become easy, and logic becomes testable.

Hope this gave you a clean and fun grasp of the Strategy Design Pattern.

Next up in the series, Observer Pattern.

Top comments (0)