文章目录
一、引入
Build:建造和构建具有建筑结构的大型物体
- 建楼:打牢地基、搭建框架、然后自下而上一层层盖起来。
- 构建物体:通常需要先建造组成这个物体的各个部分,然后分阶段把它们组装起来
二、建造者模式
2.1 Intent 意图
- Separate the construction of a complex object from its representation so that the same construction process can create different representations. 将复杂对象的构造与其表示分开,以便相同的构造过程可以创建不同的表示.
2.2 Applicability 适用性
- the algorithm for creating a complex object should be independent of the parts that make up the object and how they’re assembled. 创建复杂对象的算法应该独立于组成对象的部分以及它们的组装方式.
- 独立于:复杂对象的各个部分可能面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定
- the construction process must allow different representations for the object that’s constructed. 构造过程必须允许所构造对象的不同表示.
(将变与不变分隔开)
2.3 类图
- Builder: specifies an abstract interface for creating parts of a Product object. 指定用于创建产品对象部件的抽象接口.
- ConcreteBuilder:
- Constructs and assembles parts of the product. 建造和组装产品的部分部件
- Defines and keeps track of the representation it creates. 定义并跟踪它所创建的表示
- Provides an interface (method) for retrieving the product. 提供了一个用于检索产品的接口(方法)
- Director: constructs an object using the Builder interface. 使用 Builder 接口构造一个对象
- Product: represents the complex object under construction. 表示正在构建的复杂对象
2.4 Collaborations 合作
- The client creates the Director object and configures it with the desired Builder object.
- new Director(new ConcreteBuilder())
- Director notifies the builder whenever a part of the product should be built. Director 会告知 builder 何时应创建产品的(哪个)部件
- constract()
- buildPart(A)
- buildPart(B)
- buildPart(…)
- constract()
- Builder handles requests from the director and adds parts to the product. Builder 处理 director 的请求,添加部件到产品
- The client retrieves the product from the builder. 客户端从 builder 取回产品.
2.5 建造者模式 VS 策略模式
- In Builder pattern, Director decides the calling sequence of the methods in Builder. 在构建器模式中,Director 决定 Builder 方法的调用顺序.
- In Template Method, the super class decides the calling sequence of the methods of subclass. 在模板方法中,超类决定子类的方法的调用顺序.
2.6 建造者模式实例:文档创建程序
- 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();
}
import java.io.*;
public class HTMLBuilder extends Builder {
private String filename; // 文件名
private PrintWriter writer; // 用于编写文件的PrintWriter
public void makeTitle(String title) { // HTML文件的标题
filename = title + ".html"; // 将标题作为文件名
try {
writer = new PrintWriter(new FileWriter(filename)); // 生成 PrintWriter
} catch (IOException e) {
e.printStackTrace();
}
writer.println("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/>\n");
writer.println("<html><head><title>" + title + "</title></head><body>"); // 输出标题
writer.println("<h1>" + title + "</h1>");
}
public void makeString(String str) { // HTML文件中的字符串
writer.println("<p>" + str + "</p>"); // 用<p>标签输出
}
public void makeItems(String[] items) { // HTML文件中的条目
writer.println("<ul>"); // 用<ul>和<li>输出
for (int i = 0; i < items.length; i++) {
writer.println("<li>" + items[i] + "</li>");
}
writer.println("</ul>");
}
public void close() { // 完成文档
writer.println("</body></html>"); // 关闭标签
writer.close(); // 关闭文件
}
public String getResult() { // 编写完成的文档
return filename; // 返回文件名
}
}
public class TextBuilder extends Builder {
private String buffer = ""; // 文档内容保存在该字段中
public void makeTitle(String title) { // 纯文本的标题
buffer += "==============================\n"; // 装饰线
buffer += "『" + title + "』\n"; // 为标题加上『』
buffer += "\n"; // 换行
}
public void makeString(String str) { // 纯文本的字符串
buffer += "- " + str + "\n"; // 为字符串添加
buffer += "\n"; // 换行
}
public void makeItems(String[] items) { // 纯文本的条目
for (int i = 0; i < items.length; i++) {
buffer += " - " + items[i] + "\n"; // 为条目添加?
}
buffer += "\n"; // 换行
}
public void close() { // 完成文档
buffer += "==============================\n"; // 装饰线
}
public String getResult() { // 完成后的文档
return buffer;
}
}
- Director
public class Director {
private Builder builder;
public Director(Builder builder) { // 因为接收的参数是Builder类的子类
this.builder = builder; // 所以可以将其保存在builder字段中
}
public void construct() { // 编写文档
builder.makeTitle("Greeting"); // 标题
builder.makeString("从早上至下午"); // 字符串
builder.makeItems(new String[]{ // 条目
"早上好。",
"下午好。",
});
builder.makeString("晚上"); // 其他字符串
builder.makeItems(new String[]{ // 其他条目
"晚上好。",
"晚安。",
"再见。",
});
builder.close(); // 完成文档
}
}
- Main Test:
public class Main {
public static void main(String[] args) {
if (args.length != 1) {
usage();
System.exit(0);
}
if (args[0].equals("plain")) {
TextBuilder textbuilder = new TextBuilder();
Director director = new Director(textbuilder);
director.construct();
String result = textbuilder.getResult();
System.out.println(result);
} else if (args[0].equals("html")) {
HTMLBuilder htmlbuilder = new HTMLBuilder();
Director director = new Director(htmlbuilder);
director.construct();
String filename = htmlbuilder.getResult();
System.out.println(filename + "文件编写完成。");
} else {
usage();
System.exit(0);
}
}
public static void usage() {
System.out.println("Usage: java Main plain 编写纯文本文档");
System.out.println("Usage: java Main html 编写HTML文档");
}
}
2.6 建造者模式实例:JDK 中的应用
2.6.1 StringBuilder\StringBuffer
- ConcreteBuilder:StringBuilder\StringBuffer(父类:AbstractStringBuilder)
- AbstractBuilder:AbstractStringBuilder
2.6.2 java.sql.PreparedStatement
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00)
pstmt.setInt(2, 110592)