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

データの集まりを順番に取り出していく場合に使用されるデザインパターンです。

連番系データに対して for 文による走査でデータの取り出しをおこなうのではなく、データ構造を走査に適した形に保持しておき、ただの Array であれ、Vector であれ、 XML 中の連続データであれ、構造体であれ、イテレータ外からは next() と hasNext() で取り出しができます。コレクション内部がどういう形態であれ、それを隠ぺいできることがメリットです。

デメリットはデータ走査ごときにクラスを作る必要があるのか?ということ。オーバーヘッドが大きいという噂もありますが、そうでもない気がします。単純に手間というだけのような気がします。

ActionScript: IIterator.as

package jp.feb19.gof.iterator
{
	public interface IIterator
	{
		function hasNext():Boolean;
		function next():Object;
	}
}

ActionScript: Iterator.as

package jp.feb19.gof.iterator
{
	public class Iterator implements IIterator
	{
		private var _collection:Collection;
		private var _index:uint;
		
		public function Iterator(collection:Collection)
		{
			_collection = collection;
			_index = 0;
		}
		
		public function hasNext():Boolean
		{
			return _collection.length > _index;
		}
		
		public function next():Object
		{
			return _collection.getItemAt(_index++);
		}
	}
}

ActionScript: ICollection.as

package jp.feb19.gof.iterator
{
	public interface ICollection
	{
		function iterator():IIterator;
	}
}

ActionScript: Collection.as

package jp.feb19.gof.iterator
{
	public class Collection implements ICollection
	{
		private var _list:Array;
		
		public function Collection()
		{
			_list = [];
		}
		
		public function iterator():IIterator
		{
			return new Iterator(this);
		}
		
		public function addItem(item:Item)
		{
			_list.push(item);
		}
		
		public function getItemAt(index:uint):Item
		{
			return _list[index];
		}
		
		public function get length():uint
		{
			return _list.length;
		}
	}
}

ActionScript: Item.as

package jp.feb19.gof.iterator
{
	public class Item
	{
		private var _name:String;
		private var _url:String;
		
		public function Item(name:String, url:String)
		{
			_name = name;
			_url = url;
		}
		
		public function get name():String
		{
			return _name;
		}
		
		public function get url():String
		{
			return _url;
		}
	}
}

テストクラス

ActionScript: IteratorTest.as

package jp.feb19.gof.iterator
{
	import flash.display.Sprite;
	
	public class IteratorTest extends Sprite
	{
		public function IteratorTest()
		{
			var collection:Collection = new Collection();
			collection.addItem(new Item("UNKO", "unko"));
			collection.addItem(new Item("UNKOUNKO", "unkounko"));
			collection.addItem(new Item("U.N.K.O.", "u.n.k.o."));
			
			var it:IIterator = collection.iterator();
			while(it.hasNext())
			{
				var item:Item = it.next() as Item;
				trace(item.name, item.url);
			}
		}
	}
}

出力:

UNKO unko
UNKOUNKO unkounko
U.N.K.O. u.n.k.o.

イテレータ内での next / hasNext を応用して prev / hasPrev とかを作ることで、昇順・降順・シャッフル順とすることでき、データ管理系の便利クラスにできるかもしれません。

比較的デザインパターンでは使いやすいので使われているのをよく見かけます。