Strategy Pattern in Java
A food delivery app charges delivery in different ways: a flat fee, free above a minimum order, or extra at peak hours. The checkout code shouldn't care which rule is in force today. The Strategy pattern puts each rule (each "strategy") in its own class behind one interface, and the checkout simply calls the interface. Changing the rule means plugging in a different object, even while the program runs.
Delivery-Fee Strategies
public class Delivery {
interface DeliveryFee {
long fee(long orderAmount);
}
static class FlatFee implements DeliveryFee {
public long fee(long orderAmount) { return 40; }
}
static class FreeAbove implements DeliveryFee {
private final long minimum;
FreeAbove(long minimum) { this.minimum = minimum; }
public long fee(long orderAmount) {
return orderAmount >= minimum ? 0 : 40;
}
}
static class PeakHour implements DeliveryFee {
public long fee(long orderAmount) { return 40 + 30; }
}
static class Checkout {
private DeliveryFee feeRule;
Checkout(DeliveryFee feeRule) { this.feeRule = feeRule; }
void setFeeRule(DeliveryFee feeRule) { this.feeRule = feeRule; }
long total(long orderAmount) {
return orderAmount + feeRule.fee(orderAmount);
}
}
public static void main(String[] args) {
Checkout checkout = new Checkout(new FlatFee());
System.out.println("Navika, flat fee: Rs. " + checkout.total(350));
checkout.setFeeRule(new FreeAbove(499));
System.out.println("Srihitha, free above 499: Rs. "
+ checkout.total(620));
checkout.setFeeRule(new PeakHour());
System.out.println("Advitha, peak hour: Rs. " + checkout.total(350));
checkout.setFeeRule(amount -> amount > 1000 ? 0 : 25);
System.out.println("Festival rule: Rs. " + checkout.total(1200));
}
}Navika, flat fee: Rs. 390
Srihitha, free above 499: Rs. 620
Advitha, peak hour: Rs. 420
Festival rule: Rs. 1200How it works
DeliveryFeeis the strategy interface: one method, one job.- Each rule is a separate class.
FreeAboveeven has its own setting, the minimum amount. Checkoutholds aDeliveryFeeand calls it. It contains noifabout which rule applies.setFeeRuleswaps the strategy at runtime; the nexttotal()uses the new rule.- Because
DeliveryFeehas a single method, a lambda can be a strategy too (lambdas are covered later in the course), handy for one-off rules.
Strategy Removes if-else Chains
| Without Strategy | With Strategy |
|---|---|
if (rule.equals("FLAT")) ... else if (rule.equals("PEAK")) ... inside Checkout | feeRule.fee(amount) |
A new rule means editing and retesting Checkout | A new rule is a new class |
| Rules can't be tested on their own | Each strategy is tested separately |
Combined with a factory that picks the strategy from configuration ("FLAT", "PEAK"), this is exactly how the discount if-else in Appendix G2 should be replaced: the factory chooses, the strategy calculates.
Common Mistakes
Strategies that need to know about the context's internals. Pass in what they need as arguments; keep the interface small.
A strategy for a rule that never changes. If there will only ever be one rule, a plain method is simpler.
Putting the "which strategy?" if-else back into the context. Move that choice into a factory or configuration.
Interview Corner
What is the strategy pattern?
The strategy pattern defines a family of algorithms, puts each one in its own class implementing a common interface, and makes them interchangeable. A context object holds a reference to a strategy and delegates the work to it, so behavior can be selected or changed at runtime without modifying the context. Comparator passed to sorting methods is the classic Java example, and since Java 8 lambdas make lightweight strategies easy.
What is the difference between the strategy and factory patterns?
Factory is creational: it decides which object to create. Strategy is behavioral: it lets an object's algorithm be swapped. They're often combined: a factory picks which strategy object to use, and the context then calls that strategy.
Practice
- Easy: Add a
DistanceBasedstrategy that charges Rs. 8 per kilometer, with the distance passed to its constructor. - Harder: Write
FeeRuleFactory.fromCode(String code)that returns the right strategy for"FLAT","FREE499"and"PEAK", and use it to configure the checkout from a string.
Key Takeaways
Was this tutorial helpful?