1、引入
build意为建造,builder模式即建造模式。在建造复杂的物品时,可以先建造物体各部分,再把他们组装起来,这样可以提高建造效率。建造者模式便是如此。
2、实例
在例子中,我们要基于相同的结构搭建两个不同的文档。
2.1、Builder抽象类
在抽象类中,我们规范了需要什么样的零件。
public abstract class Builder {
public abstract void makeTitle(String title);
public abstract void makeString(String str);
public abstract void makeItems(String[] items);
public abstract void close();
}
2.2、Builder类的子类实现
实现一:文本文档
public class TextBuilder extends Builder{
private StringBuffer buffer=new StringBuffer();
@Override
public void makeTitle(String title) {
buffer.append("=============================\n");
buffer.append("["+title+"]\n");
buffer.append("\n");
}
@Override
public void makeString(String str) {
buffer.append("_"+str+"\n");
buffer.append("\n");
}
@Override
public void makeItems(String[] items) {
for (String s : items) {
buffer.append(" *"+s+"\n");
}
buffer.append("\n");
}
@Override
public void close() {
buffer.append("=============================\n");
}
public String getResult() {
return buffer.toString();
}
}
实现二:HTML文档
public class HTMLBuilder extends Builder{
private String filename;
private PrintWriter printWriter;
@Override
public void makeTitle(String title) {
filename=title+".html";
try {
printWriter=new PrintWriter(filename);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
printWriter.println("<html><head><title>"+title+"</title></head><body>");
printWriter.println("<h1>"+title+"</h1>");
}
@Override
public void makeString(String str) {
printWriter.println("<p>"+str+"</p>");
}
@Override
public void makeItems(String[] items) {
printWriter.println("<ul>");
for (String item : items) {
printWriter.println("<li>"+item+"</li>");
}
printWriter.println("</ul>");
}
@Override
public void close() {
printWriter.println("</body></html>");
printWriter.close();
}
public String getResult() {
return filename;
}
}
2.3、指导建造者Director
在Director类中,规范了如何将各零件拼接
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder=builder;
}
public void construct() {
builder.makeTitle("Greeting");
builder.makeString("从早上至下午");
builder.makeItems(new String[]{
"早上好","下午好"
});
builder.makeString("晚上");
builder.makeItems(new String[]{
"晚上好",
"晚安",
"再见"
});
builder.close();
}
}
2.4、测试
分别生成两种文档:
public class Main {
public static void main(String[] args) {
//普通文本
TextBuilder textBuilder = new TextBuilder();
Director director = new Director(textBuilder);
director.construct();
String result0 = textBuilder.getResult();
System.out.println("普通文本:"+result0);
//html
HTMLBuilder htmlBuilder = new HTMLBuilder();
director=new Director(htmlBuilder);
director.construct();
String result1 = htmlBuilder.getResult();
System.out.println("html:"+result1);
}
}
运行结果:
3、tips
-
了解template模式的同学会觉得两者很像:都是将零件拼接成复杂的成品。而两者不同在于:
- template模式是在父类中控制零件的拼接,因此子类无论如何都是生成类模板的产品,体现了“模板”的特性。
- Buider模式是通过Director类来控制零件的拼接,可以通过不同的Director来builder不同的产品,体现了“建造”。
-
谁知道什么,限制类的“认知”可以提高组件的可替换性:
- Main类没有调用Builder类中的具体函数,他只需要关注调用Director即可,这样要更换Builder类时只需要更改一处
- Director类知道要调用Builder类,但是不知道调用那个具体实现。但是它也没必要知道要用哪个具体实现,知道有Builder类中定义的方法即可,在实际问题中会为它传入实现了Builder方法的子类。正是这种无知,才给予了Builder参数的可替换性。