Decoratorパターンは既存のオブジェクトに対して、そのオブジェクトの内容(メソッドやプロパティ)を一切変更することなく、 あたかも新しい情報が加えられたかのうように振る舞わせる方法である。
同様の手法としてAdapterパターンが挙げられるが、Adapterパターンはクラス設計という意味合いが強いのに対して、 Decoratorパターンはオブジェクトそのものの設計(改造)という意味合いが強い。 オブジェクトに対するアプローチのため同じDecoratorを繰り返し使うことができる(Aapterパターンは一回のみ)。
以下の例では、Componentクラスのプロパティ_ornaments配列にDecoratorパターンを採用している。 元になるComponentクラスオブジェクトをDecoratorクラスオブジェクトでラップすることで Componentクラスオブジェクトの_ornaments配列にあたかも新しい情報が付加(decorate)されているように見えるのがわかるだろう。
最初に生成されたComponentクラスオブジェクトの内容は一切変更されていない。 ComponentクラスオブジェクトとDecoratorクラスオブジェクトは異なるオブジェクトだからである。 Decoratorクラス(Decorator1, Decorator2)は元になるComponentクラスへの参照をプロパティ(_parent)として保持しつつ、 自身もComponentクラスを継承しているため同じcomponent変数を共有することができるのである (必ずしも共有する必要はないがDecoratorパターンの特徴がわかりやすいため共有させた) また、元オブジェクトが改変されていないことを示すため またDecoratorクラスは元オブジェクトへの参照(_parent)を保持しているため decorateする直前の状態にアクセスすることが容易となっている。
//main.as package { import flash.display.Sprite; public class main extends Sprite{ public function main(){ var component:Component = new Component(); trace(component);//I wear component = new Decorator1(component); trace(component);//I wear: Decorator1 component = new Decorator2(component); trace(component);//I wear: Decorator1: Decorator2 component = component.parent; trace(component);//I wear: Decorator1 component = component.parent; trace(component);//I wear } } }
//Component.as package{ public class Component{ protected var _ornaments:Array; public function get ornaments():Array{ return _ornaments; } protected var _parent:Component; public function get parent():Component{ return _parent; } public function Component(){ _ornaments = new Array(); } public function toString():String{ var desc:String = "I wear"; for each (var decorator:String in this.ornaments){ desc += ": " + decorator ; } return desc; } } }
//ADecorator.as (Abstract class) package{ public class ADecorator extends Component{ public function ADecorator(component:Component){ _parent = component; } override public function get ornaments():Array{ return _parent.ornaments.concat(_ornaments); } } }
//Decorator1.as (Concrete class) package{ public class Decorator1 extends ADecorator{ public function Decorator1(component:Component){ super(component); _ornaments.push("Decorator1"); } } }
//Decorator2.as (Concrete class) package{ public class Decorator2 extends ADecorator{ public function Decorator2(component:Component){ super(component); _ornaments.push("Decorator2"); } } }