2015年5月31日日曜日

1-1. Abstract Factory パターン

お互いに関連・依存するクラス群を、別途生成するためのインターフェースを提供します。

一般的に関連するインスタンス群を生成するには、new Product1(); new Product2(); ...
のように直接クラスを指定して new します。
Abstract Factory パターンでは、これらを行う Factory クラスを用意し、このクラスのメソッドを介してインスタンス群の生成を行います。



サンプルでは、DOM ツリーを構築し、XML または Json で出力する例を示します。

package design_pattern;

import java.io.PrintStream;
import java.util.LinkedList;

/**
 * Abstract Factory
 * GoF, Code Complete
 * お互いに関連・依存するクラス群を、別途生成するためのインターフェースを提供します。
 * 
 * 一般的に関連するインスタンス群を生成するには、new Product1(); new Product2(); ...
 * のように直接クラスを指定して new します。
 * Abstract Factory パターンでは、これらを行う Factory クラスを用意し、
 * このクラスのメソッドを介してインスタンス群の生成を行います。
 * 
出力結果:
// Abstract Factory 未使用
<pc>
  <cpu>
    <name>
      Core i5
    </name>
    <clock>
      2GHz
    </clock>
  </cpu>
  <memory>
    <name>
      DDR2
    </name>
    <capacity>
      2GB
    </capacity>
  </memory>
</pc>
// Abstract Factory 使用
<pc>
  <cpu>
    <name>
      Core i7
    </name>
    <clock>
      3GHz
    </clock>
  </cpu>
  <memory>
    <name>
      DDR3
    </name>
    <capacity>
      4GB
    </capacity>
  </memory>
</pc>
 *
 * @author 2015/05/22 matsushima
 */
public class AbstranctFactorySample {
	/**
	 * main
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		new AbstranctFactorySample().client(args.length >= 1 ? args[0] : "xml");
	}
	
	/**
	 * Client
	 */
	void client(String type) {
		/*
		 * 一般的に関連するインスタンス群を生成するには、new Product1(); new Product2();
		 *  ... のように直接クラスを指定して new します。
		 */
		System.out.println("// Abstract Factory 未使用");
		if ("xml".equals(type)) {
			XmlElement_ConcreateProduct e1, e2, e3;
			e1 = new XmlElement_ConcreateProduct("pc");
			e1.appendChild(e2 = new XmlElement_ConcreateProduct("cpu"));
			e2.appendChild(e3 = new XmlElement_ConcreateProduct("name"));
			e3.appendChild(new XmlText_ConcreateProduct("Core i5"));
			e2.appendChild(e3 = new XmlElement_ConcreateProduct("clock"));
			e3.appendChild(new XmlText_ConcreateProduct("2GHz"));
			e1.appendChild(e2 = new XmlElement_ConcreateProduct("memory"));
			e2.appendChild(e3 = new XmlElement_ConcreateProduct("name"));
			e3.appendChild(new XmlText_ConcreateProduct("DDR2"));
			e2.appendChild(e3 = new XmlElement_ConcreateProduct("capacity"));
			e3.appendChild(new XmlText_ConcreateProduct("2GB"));
			e1.printNode(System.out, "");
		} else if ("json".equals(type)) {
			JsonElement_ConcreateProduct e1, e2, e3;
			e1 = new JsonElement_ConcreateProduct("pc");
			e1.appendChild(e2 = new JsonElement_ConcreateProduct("cpu"));
			e2.appendChild(e3 = new JsonElement_ConcreateProduct("name"));
			e3.appendChild(new JsonText_ConcreateProduct("Core i5"));
			e2.appendChild(e3 = new JsonElement_ConcreateProduct("clock"));
			e3.appendChild(new JsonText_ConcreateProduct("2GHz"));
			e1.appendChild(e2 = new JsonElement_ConcreateProduct("memory"));
			e2.appendChild(e3 = new JsonElement_ConcreateProduct("name"));
			e3.appendChild(new JsonText_ConcreateProduct("DDR2"));
			e2.appendChild(e3 = new JsonElement_ConcreateProduct("capacity"));
			e3.appendChild(new JsonText_ConcreateProduct("2GB"));
			e1.printNode(System.out, "");
		} else {
			throw new UnsupportedOperationException(type);
		}

		/*
		 * Abstract Factory パターンでは、これらを行う Factory クラスを用意し、
		 * このクラスのメソッドを介してインスタンス群の生成を行います。
		 */
		System.out.println("// Abstract Factory 使用");
		Document_AbstractFactory document;
		if ("xml".equals(type)) {
			document = new XmlDocument_ConcreateFactory();
		} else if ("json".equals(type)) {
			document = new JsonDocument_ConcreateFactory();
		} else {
			throw new UnsupportedOperationException(type);
		}
		Element_AbstractProduct e1, e2, e3;
		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"));
		e1.printNode(System.out, "");
	}

	/** Node Product インターフェース。 */
	public interface Node_AbstractProduct {
		public String getNodeName();
		public String getNodeValue();
		public void printNode(PrintStream writer, String indent);
	}
	
	/** Text Node Product 抽象クラス。 */
	public abstract class Text_AbstractProduct implements Node_AbstractProduct {
		private String value;
		protected Text_AbstractProduct(String value) {
			this.value = value;
		}
		public String getNodeName() {
			return "#text";
		}
		public String getNodeValue() {
			return this.value;
		}
	}
	
	/** Element Node Product 抽象クラス。 */
	public abstract class Element_AbstractProduct implements Node_AbstractProduct {
		private String name;
		private LinkedList<Node_AbstractProduct> children = new LinkedList<>();
		protected Element_AbstractProduct(String name) {
			this.name = name;
		}
		public String getNodeName() {
			return this.name;
		}
		public String getNodeValue() {
			return null;
		}
		public Node_AbstractProduct appendChild(Node_AbstractProduct node) {
			this.children.add(node);
			return node;
		}
		public Node_AbstractProduct removeChild(Node_AbstractProduct node) {
			this.children.remove(node);
			return node;
		}
		public Node_AbstractProduct getChild(int index) {
			return index < this.children.size() ? this.children.get(index) : null;
		}
	}
	
	/** XML Text Node Product。 */
	public class XmlText_ConcreateProduct extends Text_AbstractProduct {
		public XmlText_ConcreateProduct(String value) {
			super(value);
		}
		@Override
		public void printNode(PrintStream writer, String indent) {
			writer.println(indent + this.getNodeValue());
		}
	}
	
	/** Json Text Node Product。 */
	public class JsonText_ConcreateProduct extends Text_AbstractProduct {
		public JsonText_ConcreateProduct(String value) {
			super(value);
		}
		@Override
		public void printNode(PrintStream writer, String indent) {
			writer.println(indent + this.getNodeValue());
		}
	}
	
	/** XML Element Node Product。 */
	public class XmlElement_ConcreateProduct extends Element_AbstractProduct {
		public XmlElement_ConcreateProduct(String name) {
			super(name);
		}
		@Override
		public void printNode(PrintStream writer, String indent) {
			writer.println(indent + "<" + this.getNodeName() + ">");
			for (int i = 0; null != this.getChild(i); ++ i) {
				this.getChild(i).printNode(writer, indent + "  ");
			}
			writer.println(indent + "</" + this.getNodeName() + ">");
		}
	}
	
	/** Json Element Node Product。 */
	public class JsonElement_ConcreateProduct extends Element_AbstractProduct {
		public JsonElement_ConcreateProduct(String name) {
			super(name);
		}
		@Override
		public void printNode(PrintStream writer, String indent) {
			writer.println(indent + "{" + this.getNodeName() + ":");
			indent = indent.replace(",", "");
			for (int i = 0; null != this.getChild(i); ++ i) {
				this.getChild(i).printNode(writer, indent + (0 == i ? "  " : "  ,"));
			}
			writer.println(indent + "}");
		}
	}
	
	/** Node(Text, Element) を生成する Document Factory インターフェース。 */
	public interface Document_AbstractFactory {
		/** Element Node を生成する。 */
		public Element_AbstractProduct createElement(String name);
		/** Text Node を生成する。 */
		public Text_AbstractProduct createTextNode(String text);
	}
	
	/** XML の Node(Text, Element) を生成する Document Factory。 */
	public class XmlDocument_ConcreateFactory implements Document_AbstractFactory {
		@Override
		public Element_AbstractProduct createElement(String name) {
			return new XmlElement_ConcreateProduct(name);
		}
		@Override
		public Text_AbstractProduct createTextNode(String text) {
			return new XmlText_ConcreateProduct(text);
		}
	}
	
	/** Json の Node(Text, Element) を生成する Document Factory。 */
	public class JsonDocument_ConcreateFactory implements Document_AbstractFactory {
		@Override
		public Element_AbstractProduct createElement(String name) {
			return new JsonElement_ConcreateProduct(name);
		}
		@Override
		public Text_AbstractProduct createTextNode(String text) {
			return new JsonText_ConcreateProduct(text);
		}
	}
}

0 件のコメント:

コメントを投稿