ActionScript 3 (Flash/AIR): GoF デザインパターン – Decorator

飾り枠(Decorator)と、中身(Component)をインターフェースと委譲と継承で同一視することで、中身自身も同じデコレーションされる対象にすることが出来ます。

すると以下のようなことが出来ます。このとき、 BlueColorDecorator と BlurDecorator を入れ替えることもできます。

ActionScript: IComponent.as

package jp.feb19.gof.decorator
{
	import flash.display.Sprite;
	
	public interface IComponent
	{
		function get sprite():Sprite;
	}
}

ActionScript: CircleComponent.as

package jp.feb19.gof.decorator
{
	import flash.display.Sprite;
	
	public class CircleComponent implements IComponent
	{
		private var _sprite:Sprite;
		public function CircleComponent(sprite:Sprite)
		{
			_sprite = sprite;
			
			_sprite.graphics.beginFill(0x000000);
			_sprite.graphics.drawCircle(0, 0, 40);
			_sprite.graphics.endFill();
		}
		
		public function get sprite():Sprite
		{
			return _sprite;
		}
		
	}
}

ActionScript: Decorator.as

package jp.feb19.gof.decorator
{
	import flash.display.Sprite;
	
	public class Decorator implements IComponent
	{
		protected var _originalComponent:IComponent;
		
		public function Decorator(component:IComponent)
		{
			_originalComponent = component;
		}
		
		public function get sprite():Sprite
		{
			return _originalComponent.sprite;
		}
	}
}

ActionScript: BlueColorDecorator.as

package jp.feb19.gof.decorator
{
	import flash.geom.ColorTransform;
	
	public class BlueColorDecorator extends Decorator
	{
		public function BlueColorDecorator(component:IComponent)
		{
			super(component);
			var ct:ColorTransform = component.sprite.transform.colorTransform;
			ct.blueOffset = 255;
			component.sprite.transform.colorTransform = ct;
		}
	}
}

ActionScript: BlurDecorator.as

package jp.feb19.gof.decorator
{
	import flash.filters.BlurFilter;
	
	public class BlurDecorator extends Decorator
	{
		public function BlurDecorator(component:IComponent)
		{
			super(component);
			component.sprite.filters = [new BlurFilter(16, 16)];
		}
	}
}

ActionScript: DecoratorTest.as

package jp.feb19.gof.decorator
{
	import flash.display.Sprite;
	
	public class DecoratorTest extends Sprite
	{
		public function DecoratorTest()
		{
			super();
			
			var sprite:Sprite = new Sprite();
			
			addChild(
				new BlurDecorator(
					new BlueColorDecorator(
						new CircleComponent(sprite)
					)
				).sprite
			);
			
			sprite.x = 100.0;
			sprite.y = 100.0;
		}
	}
}

コンストラクタ引数に IComponent 型のオブジェクトを渡し、メンバ変数として保持する形が一般的なようです。

機能を細分化し、たくさんのクラスに分割できる点が特徴ですが、その分、クラスの数が多くなりやすいです。上記のような機能を提供するライブラリを制作しておくと色々便利かもしれません。