2015年6月19日金曜日

1-16. Iterator パターン

集合オブジェクトの内部を公開せずに、要素への順次にアクセスする方法を提供します。



ConcreteAggregate は String 配列の集合オブジェクトを持ちますが、Iterator のインターフェース
によってそれを意識せずに順次アクセスすることができます。
void client() {
	Aggregate aggregate = new ConcreteAggregate("aaa", "bbb", "ccc");
	System.out.println("// Iterator 未使用");
	String[] list = ((ConcreteAggregate)aggregate).list;
	for (int i = 0; i < list.length; ++ i) {
		System.out.print(list[i] + ", ");
	}
	System.out.println();
	System.out.println("// Iterator 使用");
	Iterator iterator = aggregate.iterator();
	while (iterator.hasNext()) {
		System.out.print(iterator.next() + ", ");
	}
	System.out.println();
}
interface Aggregate {
	public Iterator iterator();
}
interface Iterator {
	public boolean hasNext();
	public String next();
}
class ConcreteAggregate implements Aggregate {
	public String[] list;
	public ConcreteAggregate(String... strings) {
		this.list = strings;
	}
	public Iterator iterator() {
		return new ConcreteIterator(this);
	}
}
class ConcreteIterator implements Iterator {
	private ConcreteAggregate aggregate;
	private int index = 0;
	public ConcreteIterator(ConcreteAggregate aggregate) {
		this.aggregate = aggregate;
	}
	public boolean hasNext() {
		return (this.index < this.aggregate.list.length);
	}
	public String next() {
		if (!this.hasNext()) {
			throw new NoSuchElementException();
		}
		return this.aggregate.list[this.index ++];
	}
}
出力結果:
// Iterator 未使用
aaa, bbb, ccc, 
// Iterator 使用
aaa, bbb, ccc, 
サンプルプログラムとして、DOM ノードの子供のノードを Iterator パターンで実装する例を示し
ます。
Iterator インターフェースとして標準ライブラリの Iterator インターフェースを、
同様に Aggregate は Iterable を使用しています。また、Iterable インターフェースを実装する
ことで、順次アクセスに foreach 文を使用することができます。
出力結果:
// Iterator パターン未使用
<root>
  <entry><name>Google</name><URL>http://www.google.co.jp/</URL></entry>
  <entry><name>Yahoo</name><URL>http://www.yahoo.co.jp/</URL></entry>
  <entry><name>bing</name><URL>http://www.bing.com/</URL></entry>
</root>
// Iterator パターン使用
<root>
  <entry><name>Google</name><URL>http://www.google.co.jp/</URL></entry>
  <entry><name>Yahoo</name><URL>http://www.yahoo.co.jp/</URL></entry>
  <entry><name>bing</name><URL>http://www.bing.com/</URL></entry>
</root>
// Iterator パターン使用 + foreach
<root>
  <entry><name>Google</name><URL>http://www.google.co.jp/</URL></entry>
  <entry><name>Yahoo</name><URL>http://www.yahoo.co.jp/</URL></entry>
  <entry><name>bing</name><URL>http://www.bing.com/</URL></entry>
</root>
package design_pattern;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Iterator
 * GoF, Code Complete
 * 
 * 集合オブジェクトの内部を公開せずに、要素への順次にアクセスする方法を提供します。
 * 
 * @author 2015/05/29 matsushima
 */
public class IteratorSample {
	/**
	 * main
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		new IteratorSample().client();
	}
	/**
	 * client
	 */
	void client() {
		Document_ConcreteAggregate document = new Document_ConcreteAggregate();
		Element_ConcreteAggregate root = document.createElement("root");
		document.appendChild(root);
		root.appendChild(document.createTextNode("\n  "));
		Element_ConcreteAggregate element;
		root.appendChild(element = document.createElement("entry"));
		element.appendChild(document.createElement("name"))
				.appendChild(document.createTextNode("Google"));
		element.appendChild(document.createElement("URL"))
				.appendChild(document.createTextNode("http://www.google.co.jp/"));
		root.appendChild(document.createTextNode("\n  "));
		root.appendChild(element = document.createElement("entry"));
		element.appendChild(document.createElement("name"))
				.appendChild(document.createTextNode("Yahoo"));
		element.appendChild(document.createElement("URL"))
				.appendChild(document.createTextNode("http://www.yahoo.co.jp/"));
		root.appendChild(document.createTextNode("\n  "));
		root.appendChild(element = document.createElement("entry"));
		element.appendChild(document.createElement("name"))
				.appendChild(document.createTextNode("bing"));
		element.appendChild(document.createElement("URL"))
				.appendChild(document.createTextNode("http://www.bing.com/"));
		root.appendChild(document.createTextNode("\n"));
		System.out.println("// Iterator パターン未使用");
		printNode("node", document.getDocumentElement());
		System.out.println();
		System.out.println("// Iterator パターン使用");
		printNode("iterator", document.getDocumentElement());
		System.out.println();
		System.out.println("// Iterator パターン使用 + foreach");
		printNode("iterable", document.getDocumentElement());
	}
	/**
	 * ノードを出力。
	 */
	void printNode(String method, Node_Aggregate node) {
		if (node instanceof Text_ConcreteAggregate) {
			System.out.print(node.getNodeValue());
		} else {
			System.out.print("<" + node.getNodeName() + ">");
		}
		if ("node".equals(method)) {
			for (Node_Aggregate child = node.getFirstChild();
					null != child; child = child.getNextSibling()) {
				this.printNode(method, child);
			}
		} else if ("iterator".equals(method)) {
			for (Iterator<Node_Aggregate> it = node.iterator(); it.hasNext(); ) {
				this.printNode(method, it.next());
			}
		} else if ("iterable".equals(method)) {
			for (Node_Aggregate child: node) {
				this.printNode(method, child);
			}
		}
		if (node instanceof Text_ConcreteAggregate) {
		} else {
			System.out.print("</" + node.getNodeName() + ">");
		}
	}

	/*
	// Iterator
	package java.util;
	public interface Iterator<E> {
	    boolean hasNext();
	    E next();
	    void remove();
	}
	// Aggregate
	package java.lang;
	import java.util.Iterator;
	public interface Iterable<T> {
	    Iterator<T> iterator();
	}
	*/
	/** Aggregate: Node インターフェース。 */
	public interface Node_Aggregate extends Iterable<Node_Aggregate> {
		public String getNodeName();
		public String getNodeValue();
		public Node_Aggregate getFirstChild();
		public Node_Aggregate getNextSibling();
		public Node_Aggregate appendChild(Node_Aggregate node);
		//public Iterator<Node> iterator(); // Iterable<Node>
	}
	/** ConcreteAggregate: Node 抽象クラス。 */
	public abstract class AbstractNode_ConcreteAggregate implements Node_Aggregate {
		private Node_Aggregate firstChild = null, lastChild = null, nextSibling = null;
		public Node_Aggregate getFirstChild() { return this.firstChild; }
		public Node_Aggregate getNextSibling() { return this.nextSibling; }
		public Node_Aggregate appendChild(Node_Aggregate node) {
			if (null == this.firstChild) { this.firstChild = node; }
			if (null != this.lastChild) {
				((AbstractNode_ConcreteAggregate)this.lastChild).nextSibling = node; }
			this.lastChild = node;
			return node;
		}
		public Iterator<Node_Aggregate> iterator() {
			return new Node_ConcreteIterator();
		}
		/** ConcreteIterator: Node の Iterator。 */
		private class Node_ConcreteIterator implements Iterator<Node_Aggregate> {
			private Node_Aggregate node = firstChild;
			public boolean hasNext() {
				return (null != this.node);
			}
			public Node_Aggregate next() {
				if (!this.hasNext()) {
					throw new NoSuchElementException();
				}
				Node_Aggregate result = this.node;
				this.node = this.node.getNextSibling();
				return result;
			}
			public void remove() {
				throw new UnsupportedOperationException();
			}
		}
	}
	/** ConcreteAggregate: Text。 */
	public class Text_ConcreteAggregate extends AbstractNode_ConcreteAggregate {
		private String value;
		public Text_ConcreteAggregate(String value) { this.value = value; }
		public String getNodeName() { return "#text"; }
		public String getNodeValue() { return this.value; }
	}
	/** ConcreteAggregate: Element。 */
	public class Element_ConcreteAggregate extends AbstractNode_ConcreteAggregate {
		private String name;
		public Element_ConcreteAggregate(String name) { this.name = name; }
		public String getNodeName() { return this.name; }
		public String getNodeValue() { return null; }
	}
	/** ConcreteAggregate: Document。 */
	public class Document_ConcreteAggregate extends AbstractNode_ConcreteAggregate {
		public String getNodeName() { return "#document"; }
		public String getNodeValue() { return null; }
		public Element_ConcreteAggregate getDocumentElement() {
			return (Element_ConcreteAggregate)this.getFirstChild();
		}
		public Element_ConcreteAggregate createElement(String name) {
			return new Element_ConcreteAggregate(name);
		}
		public Text_ConcreteAggregate createTextNode(String value) {
			return new Text_ConcreteAggregate(value);
		}
	}
}

0 件のコメント:

コメントを投稿