About Us Contact Us Write for Us Advertise
Home > System Design > Low-Level Design > Strategy Pattern in Java (with Example)
System Design › Low-Level Design

Strategy Pattern in Java (with Example)

The Strategy pattern explained: put each interchangeable algorithm in its own class behind a common interface and swap it at runtime, replacing giant if/else chains. Java code, UML, Strategy vs State, when to use.

Shiv Pandey
Shiv Pandey
Oct 22, 2026 | 19 views
Strategy Pattern in Java (with Example)

🟢 Design Patterns · Behavioral · Fresher → 🟠 senior

The Strategy pattern is the one you'll reach for most often in interviews. It lets you define a family of interchangeable algorithms, put each in its own class, and swap between them at runtime — replacing sprawling if/else chains with clean, pluggable objects. Payment methods, sorting algorithms, route planning, compression: any time there are "several ways to do X," Strategy is the answer.

In one line: Strategy defines a family of algorithms behind a common interface and makes them interchangeable at runtime, so the behaviour can be selected or swapped without changing the code that uses it.

The problem: the giant if/else

A checkout needs to support several payment methods. The naive version:

if (method.equals("CARD"))       { /* card logic */ }
else if (method.equals("UPI"))    { /* upi logic */ }
else if (method.equals("PAYPAL")) { /* paypal logic */ }
// …every new method edits this method → Open/Closed violation

Every new payment type means editing this method, it grows without bound, and unrelated logic piles into one place. That's exactly what Strategy fixes.

The solution: an interface + one class per algorithm

🟠 Define a PaymentStrategy interface; each method is its own class; a Context holds whichever strategy you choose and delegates to it:

interface PaymentStrategy { void pay(double amount); }

class CardPayment   implements PaymentStrategy { public void pay(double a){ /*…*/ } }
class UpiPayment    implements PaymentStrategy { public void pay(double a){ /*…*/ } }
class PaypalPayment implements PaymentStrategy { public void pay(double a){ /*…*/ } }

class Checkout {                                  // the context
    private PaymentStrategy strategy;
    void setStrategy(PaymentStrategy s){ this.strategy = s; }   // swap at runtime
    void checkout(double amount){ strategy.pay(amount); }       // delegate
}
// pick a strategy at runtime:
checkout.setStrategy(new UpiPayment());
checkout.checkout(499.0);
Checkout(context) PaymentStrategy CardPayment UpiPayment PaypalPayment has-a

Adding "crypto payment" is now a new class that implements the interface — zero edits to Checkout or any existing strategy. The behaviour is a plug-in.

Why it's great design

🟠 Strategy is the cleanest expression of Open/Closed (extend by adding a class) and composition over inheritance (the context has-a strategy instead of subclassing behaviour). It also makes each algorithm independently testable. When an interviewer asks "how would you avoid that if/else and make it extensible?", "extract each branch into a Strategy" is the model answer.

You've used it

Java's Collections.sort(list, comparator) is Strategy — the Comparator is a pluggable comparison algorithm. Thread pools take a RejectedExecutionHandler strategy. Any API that accepts a "policy" or "handler" object is using Strategy.

Strategy vs State (a common mix-up)

🟠 Structurally, Strategy and the State pattern look identical (a context delegating to an interface). The difference is intent: with Strategy, the client chooses the algorithm and it doesn't change itself; with State, the object transitions between states on its own as things happen. Same shape, different purpose.

When to use it

Use Strategy when you have multiple interchangeable ways to do one thing, selected at runtime, and you want to avoid conditionals and keep them extensible: payment methods, sorting/ranking, compression formats, routing algorithms, pricing rules, discount policies. If there's genuinely only ever one algorithm, don't add the indirection.

The interview-ready summary

"Strategy puts each algorithm in its own class behind a common interface, and a context holds one and delegates to it — so I can swap behaviour at runtime and add new algorithms as new classes with no edits elsewhere. It replaces a growing if/else/switch, and it's the clean expression of Open/Closed and composition over inheritance. Java's Comparator in Collections.sort is a real example. It looks like State but here the client chooses the algorithm rather than the object transitioning itself." That's the most-reached-for pattern, nailed."

What to read next

← Composite pattern · Observer pattern →

Related Articles

Chain of Responsibility Pattern in Java (Example)
System Design › Low-Level Design

Chain of Responsibility Pattern in Java (Example)

Template Method Pattern in Java (with Example)
System Design › Low-Level Design

Template Method Pattern in Java (with Example)

Command Pattern in Java (with Undo Example)
System Design › Low-Level Design

Command Pattern in Java (with Undo Example)

State Pattern in Java (with Example)
System Design › Low-Level Design

State Pattern in Java (with Example)