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/Iterator and 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
Template Method — the algorithm is fixed, the steps are not
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
}
Marking the template method `final` is deliberate — it protects the algorithm's structure from being reordered by a careless subclass
State — an object that changes its own behavior
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
}
Without State, Order.ship() would need an if/else (or switch) on a status field, repeated at every method that behaves differently per status
Sources
  • Head First Design Patterns (2nd ed.)Ch. 8, 9, 10 — Template Method; Iterator; State