Builder パターンでは、Product を構成するオブジェクト Part を生成する Builder を用いて、
Director がオブジェクトの構築を行います。
Builder パターンの目的は、オブジェクトの生成・構築を Builder, Director に分離すること
にあります。
これにより、Builder を差し替えるだけで別の内容の Product を得ることが可能に
なります。
複数のオブジェクトを構築する場合、
Product product = new Product(); product.add(new Part1()); product.add(new Part2());Builder パターンでは、Builder 抽象クラスで個々の Part オブジェクトを生成する
インターフェースを用意し、ConcreteBuilder 派生クラスで実装します。
public interface Builder { public void buildPart1(); public void buildPart2(); } public class ConcreteBuilder1 implements Builder { private Product product; public ConcreteBuilder1(Product product) { this.product = product; } public void buildPart1() { this.product.add(new Part1()); } public void buildPart2() { this.product.add(new Part2()); } public Product getResult() { return this.product; } }Director クラス内で、これらの Builder のインターフェースを介して実際に
オブジェクトを構築します。
public class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } public void construct() { this.builder.buildPart1(); this.builder.buildPart2(); } }Client は、Builder, Director インターフェースを介してオブジェクトを
構築・取得します。
Builder builder = new ConcreateBuilder1(); Director director = new Director(builder); director.construct(); Product product = builder.getResult();これにより、Builder を差し替えるだけで別の内容の Product を得ることが可能に
なります。
Builder builder = new ConcreateBuilder2(); // 差し替え Director director = new Director(builder); director.construct(); Product product = builder.getResult();
サンプルプログラムでは、異なる構成部品からなる PC を XML, Json で構築する
Document Product の構築例を示します。
package design_pattern;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;
/**
* Builder
* GoF
* 同じ構築プロセスで別の表現を作成できるように、複合したオブジェクトの構築を分離します。
*
* Builder パターンでは、Product を構成するオブジェクト Part を生成する Builder を用いて、
* Director がオブジェクトの構築を行います。
* Builder パターンの目的は、オブジェクトの生成・構築を Builder, Director に分離すること
* にあります。
* これにより、Builder を差し替えるだけで別の内容の Product を得ることが可能に
* なります。
*
* 複数のオブジェクトを構築する場合、
* <pre>
* Product product = new Product();
* product.add(new Part1());
* product.add(new Part2());
* </pre>
* Builder パターンでは、Builder 抽象クラスで個々の Part オブジェクトを生成する
* インターフェースを用意し、ConcreteBuilder 派生クラスで実装します。
* <pre>
* public interface Builder {
* public void buildPart1();
* public void buildPart2();
* }
* public class ConcreteBuilder1 implements Builder {
* private Product product;
* public ConcreteBuilder1(Product product) { this.product = product; }
* public void buildPart1() { this.product.add(new Part1()); }
* public void buildPart2() { this.product.add(new Part2()); }
* public Product getResult() { return this.product; }
* }
* </pre>
* Director クラス内で、これらの Builder のインターフェースを介して実際に
* オブジェクトを構築します。
* <pre>
* public class Director {
* private Builder builder;
* public Director(Builder builder) { this.builder = builder; }
* public void construct() {
* this.builder.buildPart1();
* this.builder.buildPart2();
* }
* }
* </pre>
* Client は、Builder, Director インターフェースを介してオブジェクトを
* 構築・取得します。
* <pre>
* Builder builder = new ConcreateBuilder1();
* Director director = new Director(builder);
* director.construct();
* Product product = builder.getResult();
* </pre>
* これにより、Builder を差し替えるだけで別の内容の Product を得ることが可能に
* なります。
* <pre>
* Builder builder = new ConcreateBuilder2(); // 差し替え
* Director director = new Director(builder);
* director.construct();
* Product product = builder.getResult();
* </pre>
*
* サンプルプログラムでは、異なる構成部品からなる PC を XML, Json で構築する
* Document Product の構築例を示します。
*
* 出力結果:
// Builder 未使用
<PC>
<CPU>
<name>
Core i7
</name>
<clock>
3GHz
</clock>
</CPU>
<Memory>
<name>
DDR3
</name>
<capacity>
4GB
</capacity>
</Memory>
</PC>
// Builder 使用
<PC>
<CPU>
<name>
Core i7
</name>
<clock>
3GHz
</clock>
</CPU>
<Memory>
<name>
DDR3
</name>
<capacity>
4GB
</capacity>
</Memory>
</PC>
// Builder 未使用
{PC:
{CPU:
{name:
Core i5
}
,{clock:
2GHz
}
}
,{Memory:
{name:
DDR3
}
,{capacity:
2GB
}
}
}
// Builder 使用
{PC:
{CPU:
{name:
Core i5
}
,{clock:
2GHz
}
}
,{Memory:
{name:
DDR3
}
,{capacity:
2GB
}
}
}
*
* @author 2015/05/22 matsushima
*/
public class BuilderSample {
/**
* main
*
* @param args
*/
public static void main(String[] args) {
for (String type: args.length >= 1 ? args : new String[]{"xml", "json"}) {
new BuilderSample().client(type);
}
}
/**
* Client
*/
void client(String type) {
/*
* 複数のオブジェクトを構築する場合、
*/
System.out.println("// Builder 未使用");
if ("xml".equals(type)) {
Node_AbstractPart e1, e2, e3;
XmlDocument_ConcreteProduct doc1 = new XmlDocument_ConcreteProduct("XML");
doc1.appendChild(e1 = new XmlElement_ConcretePart("PC"));
e1.appendChild(e2 = new XmlElement_ConcretePart("CPU"));
e2.appendChild(e3 = new XmlElement_ConcretePart("name"));
e3.appendChild(new XmlText_ConcretePart("Core i7"));
e2.appendChild(e3 = new XmlElement_ConcretePart("clock"));
e3.appendChild(new XmlText_ConcretePart("3GHz"));
e1.appendChild(e2 = new XmlElement_ConcretePart("Memory"));
e2.appendChild(e3 = new XmlElement_ConcretePart("name"));
e3.appendChild(new XmlText_ConcretePart("DDR3"));
e2.appendChild(e3 = new XmlElement_ConcretePart("capacity"));
e3.appendChild(new XmlText_ConcretePart("4GB"));
doc1.printNode(System.out, "");
} else if ("json".equals(type)) {
Node_AbstractPart e1, e2, e3;
JsonDocument_ConcreteProduct doc2 = new JsonDocument_ConcreteProduct("Json");
doc2.appendChild(e1 = new JsonElement_ConcretePart("PC"));
e1.appendChild(e2 = new JsonElement_ConcretePart("CPU"));
e2.appendChild(e3 = new JsonElement_ConcretePart("name"));
e3.appendChild(new JsonText_ConcretePart("Core i5"));
e2.appendChild(e3 = new JsonElement_ConcretePart("clock"));
e3.appendChild(new JsonText_ConcretePart("2GHz"));
e1.appendChild(e2 = new JsonElement_ConcretePart("Memory"));
e2.appendChild(e3 = new JsonElement_ConcretePart("name"));
e3.appendChild(new JsonText_ConcretePart("DDR3"));
e2.appendChild(e3 = new JsonElement_ConcretePart("capacity"));
e3.appendChild(new JsonText_ConcretePart("2GB"));
doc2.printNode(System.out, "");
} else {
throw new UnsupportedOperationException(type);
}
/*
* Builder パターンでは、Builder 抽象クラスで個々の Part オブジェクトを生成する
* インターフェースを用意し、ConcreteBuilder 派生クラスで実装します。
* Director クラス内で、これらの Builder のインターフェースを介して実際に
* オブジェクトを構築します。
* Client は、Builder, Director インターフェースを介してオブジェクトを
* 構築・取得します。
* これにより、Builder を差し替えるだけで別の内容の Product を得ることが可能に
* なります。
*/
System.out.println("// Builder 使用");
Builder builder;
if ("xml".equals(type)) {
builder = new XmlCorei7PcConCreateBuilder("XML");
} else if ("json".equals(type)) {
builder = new JsonCorei5PcConCreateBuilder("Json");
} else {
throw new UnsupportedOperationException(type);
}
Director director = new Director(builder);
director.construct();
builder.getResult().printNode(System.out, "");
}
// Director ///////////////////////////////////////
/** Node(Text, Element) を生成する Director。 */
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
this.builder.buildPc();
this.builder.buildCpu();
this.builder.buildMemory();
}
}
// Builder ///////////////////////////////////////
/** Builder インターフェース。 */
public interface Builder {
public void buildPc();
public void buildCpu();
public void buildMemory();
public Node_AbstractPart getResult();
}
/** XML Node(Core i7 PC) を生成する Builder。 */
public class XmlCorei7PcConCreateBuilder implements Builder {
private Node_AbstractPart document;
public XmlCorei7PcConCreateBuilder(String name) {
this.document = new XmlDocument_ConcreteProduct(name);
}
public void buildPc() {
this.document.appendChild(new XmlElement_ConcretePart("PC"));
}
public void buildCpu() {
Node_AbstractPart e1, e2, e3;
e1 = this.document.getChildNodes().get(0);
e1.appendChild(e2 = new XmlElement_ConcretePart("CPU"));
e2.appendChild(e3 = new XmlElement_ConcretePart("name"));
e3.appendChild(new XmlText_ConcretePart("Core i7"));
e2.appendChild(e3 = new XmlElement_ConcretePart("clock"));
e3.appendChild(new XmlText_ConcretePart("3GHz"));
}
public void buildMemory() {
Node_AbstractPart e1, e2, e3;
e1 = this.document.getChildNodes().get(0);
e1.appendChild(e2 = new XmlElement_ConcretePart("Memory"));
e2.appendChild(e3 = new XmlElement_ConcretePart("name"));
e3.appendChild(new XmlText_ConcretePart("DDR3"));
e2.appendChild(e3 = new XmlElement_ConcretePart("capacity"));
e3.appendChild(new XmlText_ConcretePart("4GB"));
}
public Node_AbstractPart getResult() {
return this.document;
}
}
/** Json Node(Core i5 PC) を生成する Builder。 */
public class JsonCorei5PcConCreateBuilder implements Builder {
private Node_AbstractPart document;
public JsonCorei5PcConCreateBuilder(String name) {
this.document = new JsonDocument_ConcreteProduct(name);
}
public void buildPc() {
this.document.appendChild(new JsonElement_ConcretePart("PC"));
}
public void buildCpu() {
Node_AbstractPart e1, e2, e3;
e1 = this.document.getChildNodes().get(0);
e1.appendChild(e2 = new JsonElement_ConcretePart("CPU"));
e2.appendChild(e3 = new JsonElement_ConcretePart("name"));
e3.appendChild(new JsonText_ConcretePart("Core i5"));
e2.appendChild(e3 = new JsonElement_ConcretePart("clock"));
e3.appendChild(new JsonText_ConcretePart("2GHz"));
}
public void buildMemory() {
Node_AbstractPart e1, e2, e3;
e1 = this.document.getChildNodes().get(0);
e1.appendChild(e2 = new JsonElement_ConcretePart("Memory"));
e2.appendChild(e3 = new JsonElement_ConcretePart("name"));
e3.appendChild(new JsonText_ConcretePart("DDR3"));
e2.appendChild(e3 = new JsonElement_ConcretePart("capacity"));
e3.appendChild(new JsonText_ConcretePart("2GB"));
}
public Node_AbstractPart getResult() {
return this.document;
}
}
// Product ///////////////////////////////////////
/** Node Part インターフェース。 */
public interface Node_AbstractPart {
public String getNodeName();
public String getNodeValue();
public Node_AbstractPart appendChild(Node_AbstractPart node);
public List<Node_AbstractPart> getChildNodes();
public void printNode(PrintStream writer, String indent);
}
/** Node Part 抽象クラス。 */
public abstract class AbstractNode_AbstractPart implements Node_AbstractPart {
private String name, value;
private LinkedList<Node_AbstractPart> children = new LinkedList<>();
protected AbstractNode_AbstractPart(String name, String value) {
this.name = name;
this.value = value;
}
public String getNodeName() { return this.name; }
public String getNodeValue() { return this.value; }
public Node_AbstractPart appendChild(Node_AbstractPart node) {
this.children.add(node);
return node;
}
public List<Node_AbstractPart> getChildNodes() {
return this.children;
}
}
/** XML Document Product。 */
public class XmlDocument_ConcreteProduct extends AbstractNode_AbstractPart {
protected XmlDocument_ConcreteProduct(String name) { super(name, null); }
public void printNode(PrintStream writer, String indent) {
this.getChildNodes().get(0).printNode(writer, "");
}
}
/** XML Element Node Part。 */
public class XmlElement_ConcretePart extends AbstractNode_AbstractPart {
public XmlElement_ConcretePart(String name) { super(name, null); }
public void printNode(PrintStream writer, String indent) {
writer.println(indent + "<" + this.getNodeName() + ">");
for (Node_AbstractPart node: this.getChildNodes()) {
node.printNode(writer, indent + " ");
}
writer.println(indent + "</" + this.getNodeName() + ">");
}
}
/** XML Text Node Part。 */
public class XmlText_ConcretePart extends AbstractNode_AbstractPart {
public XmlText_ConcretePart(String value) { super(null, value); }
public void printNode(PrintStream writer, String indent) {
writer.println(indent + this.getNodeValue());
}
}
/** Json Document Product。 */
public class JsonDocument_ConcreteProduct extends AbstractNode_AbstractPart {
protected JsonDocument_ConcreteProduct(String name) { super(name, null); }
public void printNode(PrintStream writer, String indent) {
this.getChildNodes().get(0).printNode(writer, "");
}
}
/** Json Element Node Part。 */
public class JsonElement_ConcretePart extends AbstractNode_AbstractPart {
public JsonElement_ConcretePart(String name) { super(name, null); }
public void printNode(PrintStream writer, String indent) {
writer.println(indent + "{" + this.getNodeName() + ":");
indent = indent.replace(",", "");
for (Node_AbstractPart node: this.getChildNodes()) {
node.printNode(writer,
indent + (this.getChildNodes().get(0) == node ? " " : " ,"));
}
writer.println(indent + "}");
}
}
/** Json Text Node Part。 */
public class JsonText_ConcretePart extends AbstractNode_AbstractPart {
public JsonText_ConcretePart(String value) { super(null, value); }
public void printNode(PrintStream writer, String indent) {
writer.println(indent + this.getNodeValue());
}
}
}
0 件のコメント:
コメントを投稿