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

複数の様々なオブジェクト(機能)を持ったクラスを作りたいときにそれらをまとめるクラスを作っておくと、便利、ってことだと思います。

あんまりよくわかりませんが、インターフェースで IBuilder を用意しておいて、それを実装したクラスで組み立てるようにしておき、実装クラスのインスタンスは IBuilder インスタンスにしておくことでどんなビルダークラスだろうが組み立てて結果を得ることができます的なことのようです。

ActionScript: IBuilder.as

package jp.feb19.gof.builder
{
	public interface IBuilder
	{
		function buildEye():void;
		function buildNose():void;
		function buildMouth():void;
		function buildEar():void;
		function getResult():Product;
	}
}

ActionScript: Director.as

package jp.feb19.gof.builder
{
	public class Director
	{
		public function Director()
		{
		}
		
		public function construct(builder:IBuilder):void
		{
			builder.buildEye();
			builder.buildNose();
			builder.buildMouth();
			builder.buildEar();
		}
	}
}

ActionScript: Product.as

package jp.feb19.gof.builder
{
	public class Product
	{
		private var features:Vector.;
//		private var features:Array;
		
		public function Product()
		{
			features = new Vector.();
//			features = [];
		}
		
		public function assemble(aspect:String):void
		{
			features.push(aspect);
		}
		
		public function disclose():void
		{
			for each (var facet:String in features)
			{
				trace(facet);
			}
			trace("");
			
			features.length = 0;
		}
	}
}

ActionScript: ConcreteBuilder1.as

package jp.feb19.gof.builder
{
	public class ConcreteBuilder1 implements IBuilder
	{
		private var _product:Product;
		public function ConcreteBuilder1()
		{
			_product = new Product;
		}
		public function buildEye():void
		{
			_product.assemble("青い");
		}
		public function buildNose():void
		{
			_product.assemble("高め");
		}
		public function buildMouth():void
		{
			_product.assemble("薄い唇");
		}
		public function buildEar():void
		{
			_product.assemble("とがっている");
		}
		public function getResult():Product
		{
			return _product;
		}
	}
}

ActionScript: ConcreteBuilder2.as

package jp.feb19.gof.builder
{
	public class ConcreteBuilder2 implements IBuilder
	{
		private var _product:Product;
		public function ConcreteBuilder2()
		{
			_product = new Product;
		}
		public function buildEye():void
		{
			_product.assemble("黒い");
		}
		public function buildNose():void
		{
			_product.assemble("低い");
		}
		public function buildMouth():void
		{
			_product.assemble("小さい");
		}
		public function buildEar():void
		{
			_product.assemble("福耳");
		}
		public function getResult():Product
		{
			return _product;
		}
	}
}

ActionScript: ConcreteBuilder3.as

package jp.feb19.gof.builder
{
	public class ConcreteBuilder3 implements IBuilder
	{
		private var _product:Product;
		public function ConcreteBuilder3()
		{
			_product = new Product;
		}
		public function buildEye():void
		{
			_product.assemble("ふつう");
		}
		public function buildNose():void
		{
			_product.assemble("ふつう");
		}
		public function buildMouth():void
		{
			_product.assemble("ふつう");
		}
		public function buildEar():void
		{
			_product.assemble("ふつう");
		}
		public function getResult():Product
		{
			return _product;
		}
	}
}

テストクラス

ActionScript: BuilderTest.as

package jp.feb19.gof.builder
{
	import flash.display.Sprite;
	
	public class BuilderTest extends Sprite
	{
		public function BuilderTest()
		{
			super();
			
			var director:Director = new Director();
			
			var builder1:IBuilder = new ConcreteBuilder1();
			director.construct(builder1);
			var product1:Product = builder1.getResult();
			product1.disclose();
			
			var builder2:IBuilder = new ConcreteBuilder2();
			director.construct(builder2);
			var product2:Product = builder2.getResult();
			product2.disclose();
			
			var builder3:IBuilder = new ConcreteBuilder3();
			director.construct(builder3);
			var product3:Product = builder3.getResult();
			product3.disclose();
		}
	}
}

出力

青い
高め
薄い唇
とがっている
 
黒い
低い
小さい
福耳
 
ふつう
ふつう
ふつう
ふつう

根底にあるのは、オブジェクト指向には「自動車」と「乗り物」をサブクラスとスーパークラスとして「汎化」「特化」の考え方があって、これでクラスを分離するという設計がありますが、自動車クラスを作ってるときに、自動車には必要なパーツがたくさんあるので、パーツで分離しようぜ、ということなのかも。