開発
Decoratorパターン
makuta
Decorate とは、「装飾する」という意味の言葉です。
Decoratorパターンは機能を一つひとつかぶせていくイメージで、既存のクラスに対する追加機能をそのクラス自身に手を加えることなく、 飾り付ける(Decorateする)感覚で実装するパターンです。
Decoratorパターンでは、新たな処理が付加された後で、更に新たな処理を付加することが可能になります。付加する部品が複数ある場合、それらを任意の順番で組み合わせることにより、非常に柔軟な造りが実現できます。
- 既存のオブジェクトの中身を変更することなく、機能を追加することができる
- 組み合わせで様々な機能を実現できる
- 継承よりも変更の影響を限定しやすい
Decorator パターンにおける「機能を追加する」ということは、 クラスにメソッドを追加する(インターフェースを拡張する)ということではなく、 あるメソッドの内容に機能を追加するという意味です。機能を追加したくてメソッドを追加する目的にはこのパターンは使えません。動的に機能の拡張ができることがミソなパターンですから、
- デコレーション(拡張)されたモノを、元のモノと同じに扱いたい
- 実行時に柔軟にデコレーションしたい
の両方が必要なとき(特に2が必要なとき)にこのパターンを使えばよいでしょう。
1だけならば継承してメソッドオーバーライドでも構わないです。
例えば、ケーキを例にしてみます。
- カステラを敷く
- クリームを塗る
- ネームプレートをつける
- カステラを敷く+クリームを塗る
- カステラを敷く+ネームプレートをつける
- クリームを塗る++ネームプレートをつける
- カステラを敷く+クリームを塗る+ネームプレートをつける
継承によってこれらのクラスを定義すれば機能拡張を行う数だけのクラスが必要になります。装飾の順番まで含めて管理しようとなると、数が更に多くなります。Decoratorパターンでは拡張する機能の一つ一つが独立したクラスになっており、実行時には、装飾者の組み合わせで対応することができます。
ちなみに、Java のクラスライブラリ等でもこのパターンは使われています。ファイル処理を行うクラスのコンストラクタには、 圧縮されたファイルを読み取るクラスや、暗号化されたファイルを読み取るクラスのインスタンスを与えることができます。 これらのクラスが、飾り付けに当たります。前述したように、飾り付けする順番は変更が効くので、圧縮してから暗号化したファイルと、暗号化してから圧縮したファイルの両方に対応できます。
最後に、同じような機能を実現するパターンにはAdapterやProxyもありますが、これらの違いを簡単に説明すると、、、
Adapter: オブジェクトの不適切なインターフェイスをラップする
Proxy: ラップするオブジェクトと同じインターフェイスを持ち、一部の機能を受け持つ
Decorator: 基本的なオブジェクトにレイヤ状に機能を追加する
です。
飾り枠と中身を同一視することで、より柔軟な機能拡張方法を提供するDecoratorパターンのお話でした。