我的公衆號原文:
建立型模式:建造者模式java
五大建立型模式之四:建造者模式。git
姓名 :建造者模式github
英文名 :Builder Pattern設計模式
價值觀 :專治丟三落四ide
我的介紹 :ui
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。
(來自《設計模式之禪》)設計
今天給你們介紹的是建造者模式。建造者模式的使用場景是:建立複雜的對象。什麼才能算複雜對象?若是一個對象只須要經過 new XXX() 的方式建立,那就算是一個簡單對象;若是須要 new XXX(),而且還要設置不少屬性,那這種就能夠稱爲複雜對象了,由於它的構建過程比較複雜。採用建造者模式,能夠把這個複雜的構建過程抽離開,使它不依賴建立者。下面咱們經過故事來說解。code
還記得小時候剛開始學煮湯,不瞭解怎麼煮,第一次是煮了板栗排骨湯,由於板栗比較難熟,因此是跟排骨一塊兒下鍋,而後煮了 40 分鐘,加了鹽就能夠出鍋啦。第二次煮了冬瓜排骨湯,不懂得冬瓜容易熟,就和排骨一塊兒下鍋,煮了也差很少 40 分鐘,下了鹽和香菜,發現怎麼這湯有點濃,冬瓜咋都不見了(全都煮透了),我媽看到這鍋湯,纔跟我說冬瓜容易熟,得先熬排骨,再放冬瓜進去煮。那時才發現熬湯特麼還有這差別。對象
上面是背景哈,接下來咱們來實現這個煲湯過程,冬瓜排骨湯是先加排骨,熬製 30 分鐘,加冬瓜,熬製 18 分鐘,加鹽加香菜;板栗排骨湯是先加排骨和板栗,熬製 40 分鐘,再加鹽。這湯都須要加肉、加菜、熬製、加配料。咱們使用下面代碼實現這個煲冬瓜排骨湯和板栗排骨湯的過程。接口
public class NoBuilderTest { public static void main(String[] args) { // 熬製冬瓜排骨湯 DongGuaPaiGuSoup dongGuaPaiGuSoup = new DongGuaPaiGuSoup(); // 加排骨 dongGuaPaiGuSoup.addMeat(); // 熬製 30 分鐘 dongGuaPaiGuSoup.waitMinute(30); // 加冬瓜 dongGuaPaiGuSoup.addVegetables(); // 熬製 10 分鐘 dongGuaPaiGuSoup.waitMinute(10); // 加鹽加香菜 dongGuaPaiGuSoup.addIngredients(); // 熬製板栗排骨湯 BanLiPaiGuSoup banLiPaiGuSoup = new BanLiPaiGuSoup(); // 加排骨 banLiPaiGuSoup.addMeat(); // 加板栗 banLiPaiGuSoup.addVegetables(); // 熬製 40 分鐘 banLiPaiGuSoup.waitMinute(40); // 加鹽 banLiPaiGuSoup.addIngredients(); } } /** * 煲湯接口 */ interface Soup { /** 加肉 */ void addMeat(); /** 加菜 */ void addVegetables(); /** 熬製 */ void waitMinute(int minute); /** 加配料 */ void addIngredients(); } /** * 冬瓜排骨湯 */ class DongGuaPaiGuSoup implements Soup { @Override public void addMeat() { System.out.println("加排骨"); } @Override public void addVegetables() { System.out.println("加冬瓜"); } @Override public void waitMinute(int minute) { System.out.println("熬製 " + minute + " 分鐘"); } @Override public void addIngredients() { System.out.println("加鹽、加香菜"); } } /** * 板栗排骨湯 */ class BanLiPaiGuSoup implements Soup { @Override public void addMeat() { System.out.println("加排骨"); } @Override public void addVegetables() { System.out.println("加板栗"); } @Override public void waitMinute(int minute) { System.out.println("熬製 " + minute + " 分鐘"); } @Override public void addIngredients() { System.out.println("加鹽"); } }
上面代碼簡單實現了煲冬瓜排骨湯和板栗排骨湯。煲湯咱們要關注的點是:各操做的順序,是先加肉先煮再加菜,仍是肉和菜一塊兒放進鍋煮。上面代碼中,這個過程是誰控制的?是煲湯的人,因此順序由煲湯的人決定,甚至有可能忘記放配料啥的,這樣子的湯就味道不夠好。那怎麼去解決這些問題?
咱們經過建造者模式能夠解決上面的 2 個問題:煲湯順序問題和忘記加配料這種丟三落四行爲。咱們將這個煲湯順序從煲湯者分離開來,讓煲湯者只須要決定煲什麼湯就好,讓建造者來保證煲湯順序問題和防止漏加配料。
咱們用一個 SoupBuilder 來規範化煲湯過程,方法 buildSoup 給實現者提供一個設置煲湯順序的地方。由於冬瓜排骨湯和板栗排骨湯熬製的過程不同,因此分別用 DongGuaPaiGuSoupBuilder 和 BanLiPaiGuSoupBuilder 來具體實現冬瓜排骨湯和板栗排骨湯的熬製過程,也就是消除熬製過程和煲湯者的依賴關係。 Director 則至關於一個菜單,提供爲熬湯者來選擇熬什麼湯。具體代碼以下所示。
public class BuilderTest { public static void main(String[] args) { Director director = new Director(); // 熬製冬瓜排骨湯 director.buildDongGuaPaiGuSoup(); // 熬製板栗排骨湯 director.buildBanLiPaiGuSoup(); } } /** * 煲湯建造接口 */ interface SoupBuilder { void buildSoup(); Soup getSoup(); } /** * 冬瓜排骨湯建造者 */ class DongGuaPaiGuSoupBuilder implements SoupBuilder { private DongGuaPaiGuSoup dongGuaPaiGuSoup = new DongGuaPaiGuSoup(); @Override public void buildSoup() { // 加排骨 dongGuaPaiGuSoup.addMeat(); // 熬製 30 分鐘 dongGuaPaiGuSoup.waitMinute(30); // 加冬瓜 dongGuaPaiGuSoup.addVegetables(); // 熬製 10 分鐘 dongGuaPaiGuSoup.waitMinute(10); // 加鹽加香菜 dongGuaPaiGuSoup.addIngredients(); } @Override public Soup getSoup() { return dongGuaPaiGuSoup; } } /** * 板栗排骨湯建造者 */ class BanLiPaiGuSoupBuilder implements SoupBuilder { BanLiPaiGuSoup banLiPaiGuSoup = new BanLiPaiGuSoup(); @Override public void buildSoup() { // 加排骨 banLiPaiGuSoup.addMeat(); // 加板栗 banLiPaiGuSoup.addVegetables(); // 熬製 40 分鐘 banLiPaiGuSoup.waitMinute(40); // 加鹽 banLiPaiGuSoup.addIngredients(); } @Override public Soup getSoup() { return banLiPaiGuSoup; } } /** * 生產方 */ class Director { private DongGuaPaiGuSoupBuilder dongGuaPaiGuSoupBuilder = new DongGuaPaiGuSoupBuilder(); private BanLiPaiGuSoupBuilder banLiPaiGuSoupBuilder = new BanLiPaiGuSoupBuilder(); /** * 熬製冬瓜排骨湯 */ public DongGuaPaiGuSoup buildDongGuaPaiGuSoup() { dongGuaPaiGuSoupBuilder.buildSoup(); return (DongGuaPaiGuSoup) dongGuaPaiGuSoupBuilder.getSoup(); } /** * 熬製板栗排骨湯 */ public BanLiPaiGuSoup buildBanLiPaiGuSoup() { banLiPaiGuSoupBuilder.buildSoup(); return (BanLiPaiGuSoup) banLiPaiGuSoupBuilder.getSoup(); } }
經過用建造者實現,是否是保證了熬製湯的順序而且必定會加夠料?感覺一下其中的奧祕吧。
代碼:
Builder Pattern
經過建造者模式,能夠把原本強依賴的東西解綁,不單單解決依賴問題,還提升了封裝性,讓使用者不用明白內部的細節,用上面的例子說就熬湯不用關心怎麼熬製的過程,就像咱們想喝冬瓜排骨湯,告訴媽媽,媽媽熬製,咱們並不知道是怎麼熬製的。
參考資料:《大話設計模式》、《Java設計模式》、《設計模式之禪》、《研磨設計模式》、《Head First 設計模式》
推薦閱讀:
建立型模式:單例模式
建立型模式:工廠方法
建立型模式:抽象工廠
公衆號之設計模式系列文章
但願文章對您有所幫助,設計模式系列會持續更新,感興趣的同窗能夠關注公衆號:LieBrother,第一時間獲取文章推送閱讀,也能夠一塊兒交流,交個朋友。