Builder模式
应用场景
- 需要生成的产品对象有复杂的内部结构。
- 需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
- 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
本质
- 分离整体构建算法和部件构造
优点
- 建造者模式的使用使得产品的内部表象可以独立的变化。使用建造者模式可以使客户端不必知道产品内部组成的细节。
- 每一个Builder都相对独立,而与其它的 Builder无关,有利于扩展。
- 模式所建造的最终产品更易于控制。
缺点
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
角色
-
建造者(Builder) 角色:
定义创建一一个Product对象所需的各个部件的操作 -
具体建造者(Concrete Builder)角色:
实现Builder角色提供的接口,一步一步完成创建产品实例的过程。
在建造过程完成后,提供产品的实例。 -
指导者(Director)角色:
主要用来使用 Builder接口,以一个统一的过程来构建所需要的Product对象,只调用在Builder角色中被定义的方法。 -
产品(Product)角色:
产品便是建造中的复杂对象。
Builder模式的类图
示例程序
示例程序的类图
示例代码
public abstract class Builder {
public abstract void makeHead(String str);
public abstract void makeBody(String[] str);
public abstract void makeEnd(String str);
public abstract void close();
}
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.makeHead("901645165,2020416");
builder.makeBody(new String [] {
"数据1","数据2"
});
builder.makeEnd("Liu Dawei");
builder.close();
}
}
public class TextBuilder extends Builder {
private StringBuffer buffer=new StringBuffer();
@Override
public void makeHead(String str) {
buffer.append("文件头:"+str);
buffer.append("\n");
}
@Override
public void makeBody(String[] str) {
for(int i=0;i<str.length;i++) {
buffer.append(" "+str[i]);
}
buffer.append("\n");
}
@Override
public void makeEnd(String str) {
buffer.append("输出人"+str);
}
@Override
public void close() {
return;
}
public String getResult() {
return buffer.toString();
}
}
public class XMLBuilder extends Builder {
private String filename;
private PrintWriter writer;
@Override
public void makeHead(String str) {
filename = "111.xml";
try {
writer = new PrintWriter(new FileWriter(filename));
} catch (IOException e) {
e.printStackTrace();
}
writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?><bookstore>");
writer.println("<name>" + str + "</name>");
}
@Override
public void makeBody(String[] str) {
for (int i = 0; i < str.length; i++) {
writer.println("<name>" + str[i] + "</name>");
writer.println("</bookstore>");
}
}
@Override
public void makeEnd(String str) {
writer.println("<name>"+str+"</name>");
}
@Override
public void close() {}
public String getResult() {
return writer.toString();
}
}
public class Main {
public static void main(String[] args) {
if(args.length!=1) {
usage();
System.exit(0);
}
if (args[0].equals("Text")) {
TextBuilder textBuilder = new TextBuilder();
Director director = new Director(textBuilder);
director.construct();
String result = textBuilder.getResult();
System.out.println(result);
}else if(args[0].equals("XML")) {
XMLBuilder xmlbuilder = new XMLBuilder();
Director director = new Director(xmlbuilder);
director.construct();
String filename = xmlbuilder.getResult();
System.out.println(filename + "文件编写完成。");
}else {
usage();
System.exit(0);
}
}
private static void usage() {
System.out.println("Usage: Java Main Text");
System.out.println("Usage: Java Main XML");
}
}
拓展思路
- Director决定了Builder角色中方法的调用顺序。
相关设计模式
-
Template Method模式
在Builder模式中,Director 角色控制Builder角色。
在Template Method模式中,父类控制子类。 -
Composite 模式
有些情况下Builder模式生成的实例构成了Composite模式。 -
Abstract Factory模式
Builder模式和Abstract Factory模式都用于生成复杂的实例。 -
Facade模式
在Builder模式中,Director 角色通过组合Builder角色中的复杂方法向外部提供可以简单生成实例的接口( API)(相当于示例程序中的construct方法)。
Facade模式中的Facade角色则是通过组合内部模块向外部提供可以简单调用的接口(API)
满足的原则
- 开放封闭原则