[設計模式] - 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模式可以說是很好地踐行了里氏替換原則。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章