Strategy Pattern with Lambdas
Implement the Strategy pattern using interfaces and Java lambdas for flexible algorithm selection.
import java.util.*;
import java.util.function.UnaryOperator;
// Strategy interface
@FunctionalInterface
interface PricingStrategy {
double calculate(double basePrice, int quantity);
}
// Concrete strategies
class RegularPricing implements PricingStrategy {
public double calculate(double basePrice, int quantity) {
return basePrice * quantity;
}
}
class BulkPricing implements PricingStrategy {
public double calculate(double basePrice, int quantity) {
double discount = quantity >= 100 ? 0.20 : quantity >= 50 ? 0.10 : 0;
return basePrice * quantity * (1 - discount);
}
}
// Context
class ShoppingCart {
private PricingStrategy strategy;
private final List<Item> items = new ArrayList<>();
record Item(String name, double price, int quantity) {}
public ShoppingCart(PricingStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(PricingStrategy strategy) {
this.strategy = strategy;
}
public void addItem(String name, double price, int qty) {
items.add(new Item(name, price, qty));
}
public double total() {
return items.stream()
.mapToDouble(i -> strategy.calculate(i.price(), i.quantity()))
.sum();
}
}
public class StrategyDemo {
public static void main(String[] args) {
var cart = new ShoppingCart(new RegularPricing());
cart.addItem("Widget", 10.0, 5);
System.out.println("Regular: $" + cart.total()); // $50.0
cart.setStrategy(new BulkPricing());
System.out.println("Bulk: $" + cart.total()); // $50.0 (< 50 qty)
// Lambda strategy — no class needed
cart.setStrategy((price, qty) -> price * qty * 0.85); // 15% off
System.out.println("Holiday: $" + cart.total()); // $42.5
// Method reference as strategy
cart.setStrategy(StrategyDemo::premiumPricing);
}
static double premiumPricing(double price, int qty) {
return price * qty * 1.10; // 10% premium
}
}Use Cases
- Swappable pricing or discount algorithms
- Pluggable validation or sorting strategies
- Runtime algorithm selection without if-else chains
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Decorator Pattern — OOP and Functional
Implement the decorator pattern both classically and with functional composition for flexible behavior.
Best for: Adding behavior to objects without subclassing
Java Streams — Filter, Map, Collect
Process collections with Java Streams: filter, map, flatMap, reduce, and collect to lists or maps.
Best for: Transforming and filtering collections
Builder Pattern — Fluent Object Construction
Implement the Builder pattern for complex objects with validation, immutability, and method chaining.
Best for: Constructing complex objects with many optional parameters
Singleton Pattern — Thread-Safe Approaches
Implement thread-safe singletons in Java: enum, holder class, double-checked locking, and eager init.
Best for: Application-wide configuration managers