17 March 2008

Design patterns

Design patterns are names given to object-oriented coding idioms. They are great because they facilitate communication. Unfortunately, most descriptions use UML pictures surrounded by pompous text and big examples.

When I say ..., I mean code that looks like ..., sort of.

Abstract factory:

interface Thing {}
interface Factory { Thing mk(/*...*/); }

Factory method:

interface Thing {}
abstract class Base {
  abstract Thing mk(/*...*/);
  /* do stuff */
}

Builder:

class Thing {/*...*/}
interface Builder {
  void mkNew();
  void buildPartA(/*...*/);
  /*...*/
  void buidPartZ(/*...*/);
  Thing getResult();
}

Lazy factory / Flyweight:

class Thing {
  private static final Map<String,Thing> inst = new HashMap<String,Thing>();
  private Thing(String args) {/*initialize from args*/}
  public static get(String args) {
    Thing t = inst.get(args);
    if (t == null) {
      t = new Thing(args);
      inst.put(args, t);
    }
    return t;
  }
}

Prototype:

interface Prototype<T> { T clone(); }
class Thing implements Prototype<Thing> {/*...*/}

Singleton:

class Thing {
  private static inst = null;
  private Thing() {/*...*/}
  public Thing inst() {
    if (inst == null) inst = new Thing();
    return inst;
  }
}

Adapter:

interface Interface { void doA(); /*...*/ }
class Adaptee {/*...*/}
class Adapter extends Interface {
  private Adaptee adaptee;
  @Override public void doA() {
    /* do stuff, most of the work being delegated to adaptee */
  }
  /*...*/
}

Bridge:

interface LowLevel  { /*...*/ }
interface HighLevel { void doit(); /*...*/ }
class HlImpl implements HighLevel {
  private LowLevel ll;
  public HlImpl(LowLevel ll, /*...*/) {
    this.ll = ll;
    /*...*/
  }
  @Override void doit() { /* do work, using a lot methods in ll */ }
  /*...*/
}

Composite:

interface Composite { Composite get(int index); }

Decorator:

interface Thing { void doit(); /*...*/ }
abstract class Decorator implements Thing {
  protected Decorator wrapped;
}
class DecoratorA extends Decorator {
  public DecoratorA(Decorator d) { this.wrapped = wrapped; }
  @Override void doit() {
    /* do extra stuff */
    if (wrapped != null) wrapped.doit();
  }
}

Facade:

package p;

/* The operations doX use various classes in the package p,
 * are fairly high-level, and easy to understand by someone
 * not very familiar with p.
 */
class Facade {
  public void doA() {/*...*/}
  public void doB() {/*...*/}
  /*...*/
}

Proxy:

interface Thing { void doit(); }
/* Sometimes runing on a different computer */
class RealThing implements Thing {
  @Override public void doit() { /*...*/ }
}
class ProxyThing implements Thing {
  @Override public void doit() { /* use RealThing to do most of the work */ }
}

Command:

interface Closure { void go(); }

Chain of responsibility:

abstract class Chain {
  public Chain next;
  public setNext(Chain next) {
    this.next = next;
    return this;
  }
  public void doit(int mask, String arg) {
    if (handle(mask)) reallyDoit(arg);
    if (next != null) next.doit(mask, arg);
  }
  abstract protected boolean handle(int mask);
  abstract protected void reallyDoit(String arg);
}
class ChainA extends Chain { /*...*/ }
class ChainB extends Chain { /*...*/ }
class ChainC extends Chain { /*...*/ }
class User {
  void f() {
    Chain c = new ChainA().setNext(new ChainB().setNext(new ChainC()));
    /*...*/ c.doit(mask, arg); /*...*/
  }
}

Interpreter:

interface IntExpr  { int eval(); }
interface BoolExpr { boolean eval(); }
class CompareIntExpr implements BoolExpr {
  static enum CompareIntOp { LT, EQ, GT };
  CompareIntOp op;
  IntExpr left, right;
  @Override public boolean eval() {
    switch (op) {
      case LT:  return left.eval() < right.eval();
      case EQ:  return left.eval() == right.eval();
      case GT:  return left.eval() > right.eval();
    }
    assert false; return false;
  }
}
/* and many other expressions... */

Iterator:

interface Element {}
interface Iterator {
  Element value();
  void advance();
}
interface Collection {
  Iterator first();
}

Memento:

class Thing {
  public Object save() { /*...*/ }
  public void restore(Object obj) {
    Memento m = (Memento)obj;
    /* use m to populate fields */
  }
  private static class Memento { /*...*/ }
}

Observer:

interface Observer { void update(); }
interface Subject {
  void reg(Observer o);
  void unreg(Observer o);
  void notifyObservers();
}

Strategy:

interface Strategy { void execute(/*...*/); }
class Context {
  Strategy s;
  public void execute(/*...*/) { /* delegates much to s.execute() */ }
}

Template method:

abstract class Class {
  public void doit() { /* calls smallStepX */ }
  abstract void smallStepA();
  /*...*/
  abstract void smallStepZ();
}

Visitor:

interface Ast { void accept(Visitor v); }
class AstA implements Ast { @Override void accept(Visitor v) { v.visit(this); } /*...*/ }
class AstB implements Ast { @Override void accept(Visitor v) { v.visit(this); } /*...*/ }

interface Visitor {
  void visit(AstA a);
  void visit(AstB b);
}

No comments:

Post a Comment

Note: (1) You need to have third-party cookies enabled in order to comment on Blogger. (2) Better to copy your comment before hitting publish/preview. Blogger sometimes eats comments on the first try, but the second works. Crazy Blogger.