サブクラスが決定します。
Creator 抽象クラスで Product の生成を行う factory method インターフェースを用意し、
ConcreteCreator 派生クラスで生成を実装します。
これにより、ConcreteFactory を差し替えるだけで別の Product を得ることができます。
一般的に関連するインスタンス群を生成するには、直接クラス名を指定して new します。
ConcreteProduct product = new ConcreteProduct();Factory Method パターンでは、Creator 抽象クラスでこれらを行うインターフェースを
用意し、ConcreteCreator 派生クラスで実装します。
public abstract class Creator { protected abstract AbstractProduct factoryMethod(); public void anOperation() { AbstractProduct product = this.factoryMethod(); doSomething(product); } } public class ConcreteCreator extends Creator { protected AbstractProduct factoryMethod() { return new ConcreteProduct(); } }上記の例では Creator#anOperation(Template Method パターンの template method) 内で
ConcreteFactory#factoryMethod(factory method) で生成された Product に対して操作を
行っています。
そのほかにも、factory method を public にして、外部から呼び出す方法もあります。
サンプルプログラムは、入力されたテキストを解析し、XML と Json 形式で出力する例です。
出力結果:
<PC><CPU><name>Core i7</name><clock>3GHz</clock></CPU><Memory><name>DDR3</name><capacity>4GB</capacity></Memory></PC> {PC:{CPU:{name:Core i7},{clock:3GHz}},{Memory:{name:DDR3},{capacity:4GB}}}
package design_pattern;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.List;
/**
* Factory Method
* GoF, Code Complete
* オブジェクトを生成するインターフェースを定義するが、どのクラスをインスタンス化するかは
* サブクラスが決定します。
*
* Creator 抽象クラスで Product の生成を行う factory method インターフェースを用意し、
* ConcreteCreator 派生クラスで生成を実装します。
* これにより、ConcreteFactory を差し替えるだけで別の Product を得ることができます。
*
* 一般的に関連するインスタンス群を生成するには、直接クラス名を指定して new します。
* <pre>
* ConcreteProduct product = new ConcreteProduct();
* </pre>
* Factory Method パターンでは、Creator 抽象クラスでこれらを行うインターフェースを
* 用意し、ConcreteCreator 派生クラスで実装します。
* <pre>
* public abstract class Creator {
* protected abstract AbstractProduct factoryMethod();
* public void anOperation() {
* AbstractProduct product = this.factoryMethod();
* doSomething(product);
* }
* }
* public class ConcreteCreator extends Creator {
* protected AbstractProduct factoryMethod() {
* return new ConcreteProduct();
* }
* }
* </pre>
* 上記の例では Creator#anOperation(Template Method パターンの template method) 内で
* ConcreteFactory#factoryMethod(factory method) で生成された Product に対して操作を
* 行っています。
* そのほかにも、factory method を public にして、外部から呼び出す方法もあります。
*
* サンプルプログラムは、入力されたテキストを解析し、XML と Json 形式で出力する例です。
* 出力結果:
* <pre>
* <PC><CPU><name>Core i7</name><clock>3GHz</clock></CPU><Memory><name>DDR3</name><capacity>4GB</capacity></Memory></PC>
* {PC:{CPU:{name:Core i7},{clock:3GHz}},{Memory:{name:DDR3},{capacity:4GB}}}
* </pre>
*
* @author 2015/05/23 matsushima
*/
public class FactoryMethodSample {
/**
* main
*
* @param args
*/
public static void main(String[] args) {
for (String type: args.length >= 1 ? args : new String[]{"xml", "json"}) {
new FactoryMethodSample().client(type);
}
}
/**
* Client
*/
void client(String type) {
String text =
"PC:\n"
+ " CPU:\n"
+ " name:\n"
+ " Core i7\n"
+ " clock:\n"
+ " 3GHz\n"
+ " Memory:\n"
+ " name:\n"
+ " DDR3\n"
+ " capacity:\n"
+ " 4GB\n"
;
try {
Creator creator;
switch (type.toLowerCase()) {
case "xml": creator = new XmlDocument_ConcreteCreator(); break;
case "json": creator = new JsonDocument_ConcreteCreator(); break;
default: throw new UnsupportedOperationException(type);
}
creator.parse(new StringReader(text));
creator.printNode(System.out);
} catch (IOException e) {
e.printStackTrace();
}
}
// Creator ///////////////////////////////////////
/** Creator 抽象クラス。 */
public abstract class Creator extends AbstractNode_AbstractProduct {
protected Creator(String name, String value) { super(name, value); }
public void parse(Reader in) throws IOException {
LinkedList<Node_AbstractProduct> parentStack = new LinkedList<>();
parentStack.push(this);
BufferedReader reader = new BufferedReader(in);
int indent = -1;
String line;
while (null != (line = reader.readLine())) {
String nodeText = line.trim();
// 親を探す
Node_AbstractProduct parent;
for (int i = 0; i < indent - (line.length() - nodeText.length()) + 1; ++ i) {
parent = parentStack.pop();
}
parent = parentStack.peek();
// 子供を追加
Node_AbstractProduct node = parent.appendChild(nodeText.endsWith(":")
? this.createElement(nodeText.substring(0, nodeText.length() - 1))
: this.createTextNode(nodeText));
parentStack.push(node);
indent = line.length() - nodeText.length();
}
}
public void printNode(PrintStream writer) {
this.getChildNodes().get(0).printNode(writer);
writer.println();
}
protected abstract Node_AbstractProduct createElement(String name);
protected abstract Node_AbstractProduct createTextNode(String value);
}
/** XML Node を生成する Document Creator。 */
public class XmlDocument_ConcreteCreator extends Creator {
public XmlDocument_ConcreteCreator() { super("XML", null); }
protected Node_AbstractProduct createElement(String name) {
return new XmlElement_ConcreteProduct(name);
}
protected Node_AbstractProduct createTextNode(String value) {
return new XmlText_ConcreteProduct(value);
}
}
/** Json Node を生成する Document Creator。 */
public class JsonDocument_ConcreteCreator extends Creator {
public JsonDocument_ConcreteCreator() { super("Json", null); }
protected Node_AbstractProduct createElement(String name) {
return new JsonElement_ConcreteProduct(name);
}
protected Node_AbstractProduct createTextNode(String value) {
return new JsonText_ConcreteProduct(value);
}
}
// Product ///////////////////////////////////////
/** Node Product インターフェース。 */
public interface Node_AbstractProduct {
public String getNodeName();
public String getNodeValue();
public Node_AbstractProduct appendChild(Node_AbstractProduct node);
public List<Node_AbstractProduct> getChildNodes();
public void printNode(PrintStream writer);
}
/** Node Product 抽象クラス。 */
public abstract class AbstractNode_AbstractProduct implements Node_AbstractProduct {
private String name, value;
private LinkedList<Node_AbstractProduct> children = new LinkedList<>();
protected AbstractNode_AbstractProduct(String name, String value) {
this.name = name;
this.value = value;
}
public String getNodeName() { return this.name; }
public String getNodeValue() { return this.value; }
public Node_AbstractProduct appendChild(Node_AbstractProduct node) {
this.children.add(node);
return node;
}
public List<Node_AbstractProduct> getChildNodes() {
return this.children;
}
}
/** XML Element Node Product。 */
public class XmlElement_ConcreteProduct extends AbstractNode_AbstractProduct {
public XmlElement_ConcreteProduct(String name) { super(name, null); }
public void printNode(PrintStream writer) {
writer.print("<" + this.getNodeName() + ">");
for (Node_AbstractProduct node: this.getChildNodes()) {
node.printNode(writer);
}
writer.print("</" + this.getNodeName() + ">");
}
}
/** XML Text Node Product。 */
public class XmlText_ConcreteProduct extends AbstractNode_AbstractProduct {
public XmlText_ConcreteProduct(String value) { super(null, value); }
public void printNode(PrintStream writer) {
writer.print(this.getNodeValue());
}
}
/** Json Element Node Product。 */
public class JsonElement_ConcreteProduct extends AbstractNode_AbstractProduct {
public JsonElement_ConcreteProduct(String name) { super(name, null); }
public void printNode(PrintStream writer) {
writer.print("{" + this.getNodeName() + ":");
String comma = "";
for (Node_AbstractProduct node: this.getChildNodes()) {
writer.print(comma);
comma = ",";
node.printNode(writer);
}
writer.print("}");
}
}
/** Json Text Node Product。 */
public class JsonText_ConcreteProduct extends AbstractNode_AbstractProduct {
public JsonText_ConcreteProduct(String value) { super(null, value); }
public void printNode(PrintStream writer) {
writer.print(this.getNodeValue());
}
}
}
0 件のコメント:
コメントを投稿