設計模式之生成器模式(Builder Pattern)

生成器模式的核心是 ** 當構建生成一個對象的時候泪漂,需要包含多個步驟,雖然每個步驟具體的實現不同歪泳,但是都遵循一定的流程與規(guī)則 **

舉個例子萝勤,我們如果構建生成一臺電腦,那么我們可能需要這么幾個步驟

  • 需要一個主機
  • 需要一個顯示器
  • 需要一個鍵盤
  • 需要一個鼠標
  • 需要音響等

雖然我們具體在構建一臺主機的時候呐伞,每個對象的實際步驟是不一樣的敌卓,比如,有的對象構建了i7cpu的主機伶氢,有的對象構建了i5cpu的主機趟径,有的對象構建了普通鍵盤,有的對象構建了機械鍵盤等癣防。
但不管怎樣蜗巧,你總是需要經過一個步驟就是構建一臺主機,一臺鍵盤蕾盯。
對于這個例子幕屹,我們就可以使用生成器模式來生成一臺電腦,他需要通過多個步驟來生成级遭。

所以香嗓,我們可以將生成器模式理解為,假設我們有一個對象需要建立装畅,這個對象是由多個組件(Component)組合而成靠娱,每個組件的建立都比較復雜,但運用組件來建立所需的對象非常簡單掠兄,所以我們就可以將構建復雜組件的步驟與運用組件構建對象分離像云,使用builder模式可以建立锌雀。

生成器模式的類圖如下:

Paste_Image.png

下面我們就根據這個例子來實現一個生成器模式,生成一臺電腦

首先我們需要一個電腦類:

package Builder;

public class Computer {
    public String master;
    public String screen;
    public String keyboard;
    public String mouse;
    public String audio;
    public void setMaster(String master) {
        this.master = master;
    }
    public void setScreen(String screen) {
        this.screen = screen;
    }
    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }
    public void setMouse(String mouse) {
        this.mouse = mouse;
    }
    public void setAudio(String audio) {
        this.audio = audio;
    }
}

然后我們建立一個抽象的builder類:

package Builder;

public abstract class ComputerBuilder {
    
    protected Computer computer;
    
    public Computer getComputer() {
        return computer;
    }
    
    public void buildComputer() {
        computer = new Computer();
        System.out.println("生成了一臺電腦Q肝堋R改妗!");
    }

    public abstract void buildMaster();
    public abstract void buildScreen();
    public abstract void buildKeyboard();
    public abstract void buildMouse();
    public abstract void buildAudio();
}

然后我們實現兩個具體的builder類侈贷,分別是惠普電腦的builder和戴爾電腦的builder

package Builder;

public class HPComputerBuilder extends ComputerBuilder {

    @Override
    public void buildMaster() {
        // TODO Auto-generated method stub
        computer.setMaster("i7,16g,512SSD,1060");
        System.out.println("(i7,16g,512SSD,1060)的惠普主機");
    }

    @Override
    public void buildScreen() {
        // TODO Auto-generated method stub
        computer.setScreen("1080p");
        System.out.println("(1080p)的惠普顯示屏");
    }

    @Override
    public void buildKeyboard() {
        // TODO Auto-generated method stub
        computer.setKeyboard("cherry 青軸機械鍵盤");
        System.out.println("(cherry 青軸機械鍵盤)的鍵盤");
    }

    @Override
    public void buildMouse() {
        // TODO Auto-generated method stub
        computer.setMouse("MI 鼠標");
        System.out.println("(MI 鼠標)的鼠標");
    }

    @Override
    public void buildAudio() {
        // TODO Auto-generated method stub
        computer.setAudio("飛利浦 音響");
        System.out.println("(飛利浦 音響)的音響");
    }
}
package Builder;

public class DELLComputerBuilder extends ComputerBuilder {
    
    @Override
    public void buildMaster() {
        // TODO Auto-generated method stub
        computer.setMaster("i7,32g,1TSSD,1060");
        System.out.println("(i7,32g,1TSSD,1060)的戴爾主機");
    }

    @Override
    public void buildScreen() {
        // TODO Auto-generated method stub
        computer.setScreen("4k");
        System.out.println("(4k)的dell顯示屏");
    }

    @Override
    public void buildKeyboard() {
        // TODO Auto-generated method stub
        computer.setKeyboard("cherry 黑軸機械鍵盤");
        System.out.println("(cherry 黑軸機械鍵盤)的鍵盤");
    }

    @Override
    public void buildMouse() {
        // TODO Auto-generated method stub
        computer.setMouse("MI 鼠標");
        System.out.println("(MI 鼠標)的鼠標");
    }

    @Override
    public void buildAudio() {
        // TODO Auto-generated method stub
        computer.setAudio("飛利浦 音響");
        System.out.println("(飛利浦 音響)的音響");
    }


}

然后我們實現一個director類:

package Builder;

public class Director {
    
    private ComputerBuilder computerBuilder;

    public void setComputerBuilder(ComputerBuilder computerBuilder) {
        this.computerBuilder = computerBuilder;
    }
    
    public Computer getComputer() {
        return computerBuilder.getComputer();
    }
    
    public void constructComputer() {
        computerBuilder.buildComputer();
        computerBuilder.buildMaster();
        computerBuilder.buildScreen();
        computerBuilder.buildKeyboard();
        computerBuilder.buildMouse();
        computerBuilder.buildAudio();
    }

}

最后我們測試一下代碼:

package Builder;

public class ComputerCustomer {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Director director = new Director();
        
        ComputerBuilder hp = new HPComputerBuilder();
        
        director.setComputerBuilder(hp);
        
        director.constructComputer();
        
        //get the pc
        Computer pc = director.getComputer();
    }
}
Paste_Image.png

生成器模式的優(yōu)缺點

優(yōu)點

  • 將一個對象分解為各個組件
  • 將對象組件的構造封裝起來
  • 可以控制整個對象的生成過程

缺點

對不同類型的對象需要實現不同的具體構造器的類惩歉,這可能回答大大增加類的數量

生成器模式的實際應用

Builder pattern has been used in a lot of libraries. However, there is a common mistake here. Consider the following example of StringBuilder which is a class from Java standard library. Does it utilize the Builder pattern?

生成器模式在許多類庫中都使用了。但是嚴格來說俏蛮,卻有些錯誤撑蚌。
比如這個例子,我們考慮java標準庫中的StringBuilder類搏屑,它使用了生成器模式么争涌?

StringBuilder strBuilder= new StringBuilder();
strBuilder.append("one");
strBuilder.append("two");
strBuilder.append("three");
String str= strBuilder.toString();

在標準庫中,StringBuilder繼承自AbstractStringBuilder
append方法是這個生成過程中的一步辣恋,就像我們構建電腦時亮垫,先構建主機這樣的步驟一樣。
toString方法也是生成過程中的一步伟骨,而且是構建過程中的最后一步饮潦。然而,這里的不同是沒有director携狭,所以嚴格來說這不是一個標準的生成器模式继蜡。我們程序的調用者好像就是director可以生成我們自己的String。

生成器模式與工廠模式的不同

生成器模式構建對象的時候暑中,對象通常構建的過程中需要多個步驟壹瘟,就像我們例子中的先有主機鲫剿,再有顯示屏鳄逾,再有鼠標等等,生成器模式的作用就是將這些復雜的構建過程封裝起來灵莲。
工廠模式構建對象的時候通常就只有一個步驟雕凹,調用一個工廠方法就可以生成一個對象。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末政冻,一起剝皮案震驚了整個濱河市枚抵,隨后出現的幾起案子,更是在濱河造成了極大的恐慌明场,老刑警劉巖汽摹,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異苦锨,居然都是意外死亡逼泣,警方通過查閱死者的電腦和手機趴泌,發(fā)現死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拉庶,“玉大人嗜憔,你說我怎么就攤上這事∈险蹋” “怎么了吉捶?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長皆尔。 經常有香客問我呐舔,道長,這世上最難降的妖魔是什么床佳? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任滋早,我火速辦了婚禮,結果婚禮上砌们,老公的妹妹穿的比我還像新娘杆麸。我一直安慰自己,他們只是感情好浪感,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布昔头。 她就那樣靜靜地躺著,像睡著了一般影兽。 火紅的嫁衣襯著肌膚如雪揭斧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天峻堰,我揣著相機與錄音讹开,去河邊找鬼。 笑死捐名,一個胖子當著我的面吹牛旦万,可吹牛的內容都是我干的。 我是一名探鬼主播镶蹋,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼成艘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贺归?” 一聲冷哼從身側響起淆两,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拂酣,沒想到半個月后秋冰,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡婶熬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年剑勾,在試婚紗的時候發(fā)現自己被綠了光坝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡甥材,死狀恐怖盯另,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情洲赵,我是刑警寧澤鸳惯,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站叠萍,受9級特大地震影響芝发,放射性物質發(fā)生泄漏。R本人自食惡果不足惜苛谷,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一辅鲸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腹殿,春花似錦独悴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至自沧,卻和暖如春坟奥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拇厢。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工爱谁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孝偎。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓访敌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親邪媳。 傳聞我的和親對象是個殘疾皇子捐顷,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內容