Design Patterns
Behavioral Patterns II: Iterator, Template Method, State
Three more behavioral patterns: traversing a collection without exposing its internals (Iterator), fixing an algorithm's skeleton while letting subclasses vary steps (Template Method), and letting an object change its behavior as its internal state changes (State).
- Iterator: provides sequential access to elements of a collection without exposing whether it's an array, a linked list, or a tree — Java bakes this into the language via
Iterable/Iteratorand for-each - Template Method: defines an algorithm's overall structure in a base class method, deferring specific steps to subclasses via overridable "hook" methods
- State: lets an object appear to change its class at runtime by delegating behavior to one of several interchangeable State objects representing its current condition
- Template Method is inheritance-based ("is-a" — a subclass fills in the blanks); State and Strategy are composition-based ("has-a" — an interchangeable object is swapped in)
- All three trade a small amount of upfront structure for a large reduction in scattered conditional logic elsewhere in the codebase
abstract class DataProcessor {
// The template: final so subclasses can't break the sequence
public final void process() {
readData();
transformData();
writeData();
}
protected abstract void readData();
protected abstract void transformData();
protected void writeData() { System.out.println("done"); } // hook with a sensible default
}
class CsvProcessor extends DataProcessor {
protected void readData() { /* parse CSV */ }
protected void transformData() { /* CSV-specific transform */ }
// writeData: uses the default from the base class
}interface OrderState { void ship(Order order); }
class PendingState implements OrderState {
public void ship(Order order) {
order.setState(new ShippedState()); // transitions itself
System.out.println("Shipping order...");
}
}
class ShippedState implements OrderState {
public void ship(Order order) { throw new IllegalStateException("already shipped"); }
}
class Order {
private OrderState state = new PendingState();
void setState(OrderState s) { this.state = s; }
void ship() { state.ship(this); } // delegates — Order itself has no if/else on status
}