[设计模式] - No.10 Builder模式

Builder 模式

在《图解设计模式》这本书中,对Builder模式的解释是,用于组装具有复杂结构的实例的设计模式。在这里,我通过一个接地气的小例子,来描述一下Builder设计模式究竟做了什么。

加入有一天,你突然想盖一栋别墅,首先你需要找一个会盖房子的建筑师,告诉他“给我盖一个别墅”,让他帮你盖这栋房子。

建筑师并不会直接的盖房子,他只会指挥施工队盖房子。它会指挥调度施工队,先打好地基,然后搭好框架,然后一层一层盖房子,最后封顶,房子盖完了。

那么,建筑师需要知道施工队是具体怎么打地基的么?是用左手挖地基还是右手挖地基,是用空心砖盖房子还是用实心砖盖房子呢?这些建筑师都不需要知道,就像你不需要知道建筑师是怎么指挥施工队盖房子的呢。

这样的好处是什么呢?因为建筑师仅仅需要知道怎么调度施工队,而不需要聚焦于具体怎么施工,所以有一天当另外一个施工队来替换当前的施工队的时候,他依然可以很好的指挥施工队。

同时,如果有一天这个姓王的建筑师不在了,你也仅仅只需要找一个姓李的建筑师,同时也原封不动的告诉他“给我盖一个别墅”,你依然可以盖一栋别墅。

我们来看一段代码:

与盖房子不同的是,我们现在想要的是编写一个文件。首先有一个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();
}

其次有一个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();                            // 完成文档
    }
}

Directo直接调用的抽象的Builder类,而不是具体的某个Builder。就像建筑师在盖房子的时候,不会直接点名道姓的找XX施工队一样,他只需要知道自己要找一个叫施工队的团体。

最后,一个具体的Builder类,也就是你在盖房子过程中为你的建筑师找到的具体的那个施工队

import java.io.*;

public class HTMLBuilder extends Builder {
    private String filename;                                                        // 文件名
    private PrintWriter writer;                                                     // 用于编写文件的PrintWriter
    @Override
    public void makeTitle(String title) {                                           // HTML文件的标题
        filename = title + ".html";                                                 // 将标题作为文件名
        try {
            writer = new PrintWriter(new FileWriter(filename));                     // 生成 PrintWriter
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.println("<html><head><title>" + title + "</title></head><body>");    // 输出标题
        writer.println("<h1>" + title + "</h1>");
    }
    @Override
    public void makeString(String str) {                                            // HTML文件中的字符串
        writer.println("<p>" + str + "</p>");                                       // 用<p>标签输出
    }
    @Override
    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>");
    }
    @Override
    public void close() {                                                           // 完成文档
        writer.println("</body></html>");                                           // 关闭标签
        writer.close();                                                             // 关闭文件
    }
    public String getResult() {                                                     // 编写完成的文档
        return filename;                                                            // 返回文件名
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        HTMLBuilder htmlbuilder = new HTMLBuilder();
        Director director = new Director(htmlbuilder);
        director.construct();
        String filename = htmlbuilder.getResult();
        System.out.println(filename + "文件编写完成。");

    }
}

输出如下:

Greeting.html文件编写完成

Greeting.html

<html><head><title>Greeting</title></head><body>
<h1>Greeting</h1>
<p>从早上至下午</p>
<ul>
<li>早上好。</li>
<li>下午好。</li>
</ul>
<p>晚上</p>
<ul>
<li>晚上好。</li>
<li>晚安。</li>
<li>再见。</li>
</ul>
</body></html>

Builder模式具体的UML类图:

在这里插入图片描述

时序图:
在这里插入图片描述
Builder模式可以说是很好地践行了里氏替换原则。

发布了118 篇原创文章 · 获赞 140 · 访问量 25万+

猜你喜欢

转载自blog.csdn.net/tjuyanming/article/details/84784444