》》代码实践如下:
*
* 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();
}
-------------------------------------
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.close(); //完成文档
}
}
------------------------------------
/*
* Builder 类的子类,它的功能是使用纯文本编写文档,并以String
* 返回结果
*/
public class TextBuilder extends Builder{
/*
* java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区。
* 文档内容保存在该属性中
*/
private StringBuffer buffer = new StringBuffer();
public void makeTitle(String title){ //纯文本的标题
buffer.append("====================="); //装饰线
buffer.append("【"+title+"】\n"); //为标题添加【】
buffer.append("\n"); //换行
}
public void makeString(String str){ //纯文本的字符串
buffer.append("@"+str+"\n"); //为字符串添加@
buffer.append("\n"); //换行
}
public void makeItems(String[] items){ //纯文本的条目
for(int i = 0 ; i < items.length ;i++){
buffer.append("..."+items[i]+"\n"); //为条目添加
}
buffer.append("\n"); //换行
}
public void close(){ //完成文档
buffer.append("================="); //添加装饰线
}
public String getResult(){
return buffer.toString(); //将StringBuffer转化为String
}
}
---------------------------------
/*
* HTMLBuilder 类也是 Builder类的子类,它的功能是使用HTML 编写
* 文档,其返回结果是 HTML 文件的名字
*/
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;
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));
}catch(IOException e){
//使用超类java.lang.Throwable 中的public void printStackTrace()
e.printStackTrace();
}
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; //返回文件名
}
}
-------------------------------------------
/*
* Main1是 Builder模式的测试程序。
*/
public class Main1 {
public static void main(String[] args){
if(args.length !=1){
usage();
//正常终止当前正在运行的java虚拟机
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 Main1 plain 编写纯文本文档");
System.out.println("Usage:java Main1 html 编写html文档");
}
}
---------------------------
》》Builder 模式中的登场角色:
****Builder (建造者)
Builder 角色负责定义用于生成实例的接口(API),Builder 角色中准备了
用于生成实例的方法。在以上示例程序中,由Builder 类扮演此角色。
****ConcreteBuilder(具体的建造者)
ConcreteBuilder 角色是负责实现 Builder 角色的接口的类。这里定义了在
生成实例被调用的方法。此外,ConcreteBuilder 角色中定义了获取最终生成
结果的方法。在以上示例程序中,TextBuilder 和 HTMLBuilder 类扮演此角色。
****Director (监工)
Director 角色负责使用 Builder 角色的接口(API)来生成实例。它并不依赖
ConcreteBuilder 角色。为了确保 不论ConcreteBuilder 角色是如何定义的,
Director 都能正常工作,它只调用在Builder 角色中被定义的方法。在示例程序
中Director 类扮演此角色。
*****Client (使用者)
在以上示例程序中,Main1 类扮演了此角色。
--------------------------------
》》Builder 模式中的类图如下:
》》Builder 模式的时序图如下:
》》相关的设计模式:
*** Template Method 模式
*** Composite 模式
*** Abstract Factory 模式
*** Facade 模式
》》补充:-----在 Director 类中不知道自己使用的究竟是 Builder 类的哪个子类。这样是好的,
因为“只有不知道子类 才能替换”
-----正是因为不知道才能替换,正是因为可以替换,组件才具有高价值。作为设计人员,
我们必须时刻关注这种“可替换性”。
-----在 Builder 类中应当定义哪些方法是非常重要的;
Builder 类还必须能够应对将来子类可能增加的需求。