Decorator

パターンの目的

p.187,line.3-4: オブジェクトに責任を動的に追加する。Decoratorパターンは、サブクラス化よりも柔軟な機能拡張方法を提供する。

GoF パターンのクラス図

structure-08-05:decorator

MixJuice 版 Decorator (改善)

解決される GoF パターンの問題点

拡張性の問題点

p.191,line.7-9: 1.インターフェイスの一致。decoratorのインターフェイスは、それが装飾するcomponentのインターフェイスと一致していなければならない。したがって、(少なくともC++では)ConcreteDecoratorクラスは1つの共通なクラスを継承しなければならない。

補足:あらかじめ決められたインターフェース以外のオペレーションを、 component と decorator にあとから追加できない点が問題である。

対策

抽象クラス Decorator に対して、メソッド追加あるいはアブストラクトメソッド追加を行なえばよい。

結果

component と decorator に、あとからオペレーションを追加できる。アブストラクトメソッド追加を行なった場合は、すべての ConcreteDecorator に、追加されたオペレーションを実装する補完モジュールが必要になる。しかしたいていの場合は、 Decorator クラスでデフォルトの実装として、次の decorator に処理を delegate するメソッド追加すれば十分なので、補完モジュールは不要であると思われる。

構造

structure-08-07:decorator2

module original {
  define abstract class Component {
    define abstract void operation();
  }
  define class ConcreteComponent extends Component {
    void operation(){...}
  }
  define abstract class Decorator extends Component {
    Component component;
    void operation(){ component.operation(); }
  }
  define class ConcreteDecorator extends Decorator {
    void operation(){...}
  }
}
module extension extends original {
  class Component {
    define abstract void newOperation();
  }
  class ConcreteComponent {
    void newOperation(){...}
  }
  class Decorator {
    void newOperation(){ component.newOperation(); }
  }
}

MixJuice 版 Decorator (別解)

解決される GoF パターンの問題点

クラス数増加の問題点

p.190,line.30-33: 3.decoratorとそれが装飾しているcomponentは同一ではない。decoratorは、透明な囲いのように振舞う。しかし、オブジェクトの同一性という観点では、装飾されたcomponentはcomponent自体と同一ではない。したがって、 decoratorを利用するときには、オブジェクトの同一性に依存すべきではない。

p.190,line34 -p.191,line.1-4: 4.多くの小さなオブジェクト。Decoratorパターンを利用して設計したシステムは、しばしば同じように見える多くの小さなオブジェクトから構成されることになる。それらのオブジェクトは相互に関連のしかたが異なるだけで、所属するクラスや変数の値は同じである。このようなシステムは、それを理解している人にとってはカスタマイズが容易だが、それを学んだりデバッグしたりするのは困難になることがある。

対策

もし、 component の振る舞いを動的に拡張したり、複数の振る舞いを持つ component をアプリケーション内で使う必要がなければ、 Decorator パターンを用いずに、 component そのものをクラス拡張によって拡張すれば良い。これは GoF パターンの別解である。

結果

オブジェクトの同一性が保証される。クラス数がへり、プログラムの構造が簡潔になる。 Decorator pattern では component に新たなメソッドを追加することはできないが、クラス拡張ならば可能である。動的に component の振る舞いを変更したり、異なる振る舞いをする複数の component を1つのアプリケーション内で使うことはことはできなくなる。などなど。

構造

structure-08-07:decorator1

module original {
  define class Component {
    define void operation();
  }
}
module extension1 extends original {
  class Component {
    void operation(){...}
  }
}
module extension2 extends original {
  class Component {
    void operation(){...}
  }
}

MixJuice によるデザインパターン改善カタログ


田中 哲 <akr@m17n.org>, 一杉 裕志 <y-ichisugi@aist.go.jp>