Strategy in Java
Swappable algorithms, often as lambdas.
Swap the brain, keep the body
Strategy puts each algorithm behind a common interface. The *context* holds a reference to a strategy and delegates to it, so you can swap behavior at runtime without touching the context's code.
interface Route { int minutes(Trip t); }
class Navigator {
private Route route;
void use(Route r) { route = r; }
int eta(Trip t) {
return route.minutes(t);
}
}Lambdas are strategies
In modern Java a strategy is often just a functional interface plus a lambda. Comparator, Predicate and Function are ready-made strategy slots. sort() stays the same; only the comparison you plug in changes.
names.sort(Comparator.comparing(
String::length));
names.sort(Comparator.naturalOrder());
names.sort(Comparator.reverseOrder());Same sort, two strategies
What does this print?
var xs = new ArrayList<>(
List.of("pear", "fig", "apple"));
xs.sort(Comparator.comparing(String::length));
System.out.println(xs);
xs.sort(Comparator.naturalOrder());
System.out.println(xs);[fig, pear, apple] [apple, fig, pear][fig, pear, apple] [pear, fig, apple][apple, fig, pear] [fig, pear, apple]
Show the answer
First by length: fig (3), pear (4), apple (5). Then by natural (alphabetical) order: apple, fig, pear. One sort method, two plugged-in algorithms.
Replacing a mode switch
int tax(int amt, String c) {
if (c.equals("BH")) return amt / 10;
if (c.equals("UK")) return amt / 5;
return 0;
}Every new country edits this method, and each rule gets more tangled.
interface TaxRule { int apply(int amt); }
Map<String, TaxRule> rules = Map.of(
"BH", a -> a / 10,
"UK", a -> a / 5);
int tax(int amt, String c) {
return rules.getOrDefault(c, a -> 0)
.apply(amt);
}Each country is its own strategy object, looked up by key.
Strategy or Template Method?
A class Order has a private Shipping shipping field, a use(Shipping s) setter, and total() returns 50 + shipping.cost(kg). Which pattern is that, and how would Template Method differ?
Think about it, then reveal the answer
Strategy: Order delegates to a swappable object chosen at runtime (composition). Template Method would instead fix the steps in a superclass and let a subclass override the cost step (inheritance).
The strategy must fit the slot
A method reference only works if its shape matches the interface. Predicate<String> needs a method returning boolean: String::isBlank fits. String::length returns an int and String::trim returns a String, so they don't compile there.
Predicate<String> ok = String::isBlank;
Predicate<String> no = String::length;
// error: bad return typeEveryday Strategy
Pricing rules, payment routing, sorting options in a UI, retry policies: all strategies. "Replace conditional with polymorphism" is a classic refactoring and interview topic, and passing a lambda to List.sort is Strategy in one line.
Key takeaways
- The context delegates to a strategy interface
- Swap behavior without changing the context's code
- Comparator, Predicate and Function are ready-made strategy types
- Replaces if/switch chains on a 'mode' flag
💡 A GPS app lets you pick fastest, shortest or no-tolls; the map stays the same, only the routing rule changes.
The Gang of Four book (1994) catalogued 23 design patterns. It lists Strategy's other name as Policy, which is why you'll still see classes like RetryPolicy.
Practice questions
What does this print?
List<String> xs = new ArrayList<>(
List.of("kiwi", "fig", "banana"));
xs.sort(Comparator.comparing(String::length));
System.out.println(xs);
xs.sort(Comparator.reverseOrder());
System.out.println(xs);- [fig, kiwi, banana] [kiwi, fig, banana]
- [fig, kiwi, banana] [banana, fig, kiwi]
- [banana, kiwi, fig] [kiwi, fig, banana]
- [fig, kiwi, banana] [banana, kiwi, fig]
Check your answer
[fig, kiwi, banana] [kiwi, fig, banana]. First the list is ordered by length (3, 4, 6), then by reverse alphabetical order (k > f > b). Same sort method, different plugged-in strategy.
Which pattern is this?
interface Shipping { int cost(int kg); }
class Order {
private Shipping shipping;
void use(Shipping s) { shipping = s; }
int total(int kg) {
return 50 + shipping.cost(kg);
}
}- Template Method
- Decorator
- Strategy
- Observer
Check your answer
Strategy. Order delegates cost calculation to a swappable Shipping object chosen at runtime. Template Method would vary the step through subclassing instead.