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

構造を渡り歩きながら処理を行うデザインパターンです。

AS3 は Java みたいに引数違いだけど関数名が重複している関数を作る事が出来ないからちょっと無理矢理実装してみます。そんなに変わらないですけど。

データ用クラスの方では訪問回数をそれぞれ記録しています。

データと処理を分けて別々のクラスとして作るので、役割の分離が出来ると言うことが肝なのかな?
その互いのクラスが互いのメソッドを呼び出すことによって連携する「ダブルディスパッチ」というやたらカッコイイ名前の仕組みを活用します。

ActionScript: IAcceptor.as

package jp.feb19.gof.visitor
{
	public interface IAcceptor
	{
		function accept(visitor:IVisitor):void;
	}
}

ActionScript: IVisitor.as

package jp.feb19.gof.visitor
{
	public interface IVisitor
	{
		function visitAcceptor1(acceptor:Acceptor1):void
		function visitAcceptor2(acceptor:Acceptor2):void
	}
}

IAcceptor 実装クラス

ActionScript: Acceptor1.as

package jp.feb19.gof.visitor
{
	public class Acceptor1 implements IAcceptor
	{
		private var _counter:int;
		
		public function Acceptor1()
		{
			_counter=0;
		}
		
		public function accept(visitor:IVisitor):void
		{
			_counter++;
			visitor.visitAcceptor1(this);
		}
		
		public function operationA():void
		{
			trace("visit count:" + _counter);
			trace("operationA");
		}
	}
}

ActionScript: Acceptor2.as

package jp.feb19.gof.visitor
{
	public class Acceptor2 implements IAcceptor
	{
		private var _counter:int;
		
		public function Acceptor2()
		{
			_counter=0;
		}
		
		public function accept(visitor:IVisitor):void
		{
			_counter++;
			visitor.visitAcceptor2(this);
		}
		
		public function operationB():void
		{
			trace("visit count:" + _counter);
			trace("operationB");
		}
	}
}

IVisitor 実装クラス

ActionScript: Visitor1.as

package jp.feb19.gof.visitor
{
	public class Visitor1 implements IVisitor
	{
		public function Visitor1()
		{
			
		}
		
		public function visitAcceptor1(acceptor:Acceptor1):void
		{
			trace("visitor1:accept1");
			acceptor.operationA();
		}
		
		public function visitAcceptor2(acceptor:Acceptor2):void
		{
			trace("visitor1:accept2");
			acceptor.operationB();
		}
	}
}

ActionScript: Visitor2.as

package jp.feb19.gof.visitor
{
	public class Visitor2 implements IVisitor
	{
		public function Visitor2()
		{
			
		}
		
		public function visitAcceptor1(acceptor:Acceptor1):void
		{
			trace("visitor2:accept1");
			acceptor.operationA();
		}
		
		public function visitAcceptor2(acceptor:Acceptor2):void
		{
			trace("visitor2:accept2");
			acceptor.operationB();
		}
	}
}

テストクラス

ActionScript: VisitorTest.as

package jp.feb19.gof.visitor
{
	import flash.display.Sprite;
	
	public class VisitorTest extends Sprite
	{
		public function VisitorTest()
		{
			super();
			
			var acceptors:Array = [];
			
			acceptors.push(new Acceptor1());
			acceptors.push(new Acceptor2());
			
			var visitor1:Visitor1 = new Visitor1();
			var visitor2:Visitor2 = new Visitor2();
			
			var accept:IAcceptor;
			for each (accept in acceptors)
			{
				accept.accept(visitor1);
			}
			for each (accept in acceptors)
			{
				accept.accept(visitor2);
			}
		}
	}
}

出力

visitor1:accept1
visit count:1
operationA
visitor1:accept2
visit count:1
operationB
visitor2:accept1
visit count:2
operationA
visitor2:accept2
visit count:2
operationB

でもこれちょっと使い道がイマイチよく分かりません。