2015年6月10日水曜日

1-8. Composite パターン

ツリー構造にオブジェクトを構成します。個々のオブジェクトとオブジェクトの構成物は
同様にに扱えます。


このように Leaf と Composite はともに Component として扱うことができます。
    interface Component {
        public void operation();
    }
    class Leaf implements Component {
        public void operation() { System.out.println("Leaf"); }
    }
    class Composite implements Component {
        private LinkedList children = new LinkedList<>();
        public void operation() { System.out.println("Component"); }
        public void add(Component c) { this.children.add(c); }
        public void remove(Component c) { this.children.remove(c); }
        public Component getChild(int i) { return this.children.get(i); }
    }
    void client() {
        Composite composite = new Composite();
        Leaf leaf = new Leaf();
        composite.add(leaf);
        composite.operation();
        composite.getChild(0).operation();
    }

サンプルプログラムは、XML DOM の実装例です。Leaf として Node_Leaf、
Composite として Document_Composite, Element_Composite を実装しています。
実行結果:
    <xml><PC><CPU><name>Core i7<name><clock>3GHz<clock><CPU><Memory><name>DDR3<name><capacity>4GB<capacity><Memory><PC><xml>
package design_pattern;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.LinkedList;
import java.util.List;

/**
 * Composite パターン
 * GoF, Code Complete
 * ツリー構造にオブジェクトを構成します。個々のオブジェクトとオブジェクトの構成物は
 * 同様にに扱えます。
 * 
 * このように Leaf と Composite はともに Component として扱うことができます。
 * <pre>
 *     interface Component {
 *         public void operation();
 *     }
 *     class Leaf implements Component {
 *         public void operation() { System.out.println("Leaf"); }
 *     }
 *     class Composite implements Component {
 *         private LinkedList<Component> children = new LinkedList<>();
 *         public void operation() { System.out.println("Component"); }
 *         public void add(Component c) { this.children.add(c); }
 *         public void remove(Component c) { this.children.remove(c); }
 *         public Component getChild(int i) { return this.children.get(i); }
 *     }
 *     void client() {
 *         Composite composite = new Composite();
 *         Leaf leaf = new Leaf();
 *         composite.add(leaf);
 *         composite.operation();
 *         composite.getChild(0).operation();
 *     }
 * </pre>
 * 
 * サンプルプログラムは、XML DOM の実装例です。Leaf として Node_Leaf、
 * Composite として Document_Composite, Element_Composite を実装しています。
 * 実行結果:
 * <pre>
 *     <xml><PC><CPU><name>Core i7<name><clock>3GHz<clock><CPU><Memory><name>DDR3<name><capacity>4GB<capacity><Memory><PC><xml>
 * </pre>
 * 
 * @author 2015/05/26 matsushima
 */
public class CompositeSample {
	/**
	 * main
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			new CompositeSample().client();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * Client
	 */
	void client() throws IOException {
		Document_Composite document = new Document_Composite("xml");
		Element_Composite e1, e2, e3;
		document.appendChild(e1 = document.createElement("PC"));
		e1.appendChild(e2 = document.createElement("CPU"));
		e2.appendChild(e3 = document.createElement("name"));
		e3.appendChild(document.createTextNode("Core i7"));
		e2.appendChild(e3 = document.createElement("clock"));
		e3.appendChild(document.createTextNode("3GHz"));
		e1.appendChild(e2 = document.createElement("Memory"));
		e2.appendChild(e3 = document.createElement("name"));
		e3.appendChild(document.createTextNode("DDR3"));
		e2.appendChild(e3 = document.createElement("capacity"));
		e3.appendChild(document.createTextNode("4GB"));
		document.print(new OutputStreamWriter(System.out));
	}

	/** Node Component インターフェース。 */
	public interface Node_Component {
		public String getNodeName();
		public String getNodeValue();
		public Node_Component appendChild(Node_Component node);
		public List<Node_Component> getChildNodes();
	}
	/** Text Leaf クラス。 */
	public class Text_Leaf implements Node_Component {
		private String value;
		protected Text_Leaf(String value) { this.value = value; }
		public String getNodeName() { return "#text"; }
		public String getNodeValue() { return this.value; }
		public Node_Component appendChild(Node_Component node) { return null; }
		public List<Node_Component> getChildNodes() { return null; }
	}
	/** Element Composite クラス。 */
	public class Element_Composite implements Node_Component {
		private String name;
		private LinkedList<Node_Component> children = new LinkedList<>();
		protected Element_Composite(String name) { this.name = name; }
		public String getNodeName() { return this.name; }
		public String getNodeValue() { return null; }
		public Node_Component appendChild(Node_Component node) {
			this.children.add(node);
			return node;
		}
		public List<Node_Component> getChildNodes() {
			return this.children;
		}
	}
	/** Document Composite クラス。 */
	public class Document_Composite implements Node_Component {
		private String name;
		private LinkedList<Node_Component> children = new LinkedList<>();
		protected Document_Composite(String name) { this.name = name; }
		public String getNodeName() { return this.name; }
		public String getNodeValue() { return null; }
		public Node_Component appendChild(Node_Component node) {
			this.children.add(node);
			return node;
		}
		public List<Node_Component> getChildNodes() {
			return this.children;
		}
		public Element_Composite createElement(String name) { return new Element_Composite(name); }
		public Text_Leaf createTextNode(String value) { return new Text_Leaf(value); }
		public void print(Writer writer) throws IOException {
			this.printImpl(new PrintWriter(writer), this);
			writer.flush();
		}
		private void printImpl(PrintWriter writer, Node_Component node) {
			if (null == node.getChildNodes()) {
				writer.print(node.getNodeValue());
			} else {
				writer.print("<" + node.getNodeName() + ">");
				for (Node_Component child: node.getChildNodes()) {
					this.printImpl(writer, child);
				}
				writer.print("<" + node.getNodeName() + ">");
			}
		}
	}
}

0 件のコメント:

コメントを投稿