建造者模式(Builder):將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
使用情境:
- 當建立複雜物件的演算法應該獨立於該對象的組成部分以及它們的裝配方式時。
- 當構造過程必須允許被構造的對象有不同的表示時。
通用類圖:
舉例:我們生活當中有許多裝置都是以組裝的形式存在的,例如台式電腦,那麼有些廠商就會推出一些具有預設配置的組裝電腦主機(這裡可以用到模板方法模式來實現),顧客可以購買預設配置的產品,也可以要求廠商重新組裝一部不同配置不同組裝方式的主機。此時,我們就可以使用建造者模式來滿足特殊顧客的要求了。
注意到這個例子中廠商是重新組裝一部主機,即關注點是主機的每個組成部分,這就符合上面Builder模式給出的使用情境了。
簡單代碼實現如下:
//抽象產品類,使用了模板方法模式,不同產品有不同的“組成部分part” abstract class AbstractProduct{ protected abstract void part01(); protected abstract void part02(); protected abstract void part03(); //模板方法給出了預設的組裝方式,產生預設的產品 public final AbstractProduct defaultProduct() { part01(); part02(); part03(); return this;//返回當前對象,即預設組裝方式的產品 } } //具體的產品A、B,不同產品實現了不同的“組成部分part” class ConcreteProductA extends AbstractProduct{ protected void part01() { System.out.println("產品A :part01() ..."); } protected void part02() { System.out.println("產品A :part02() ..."); } protected void part03() { System.out.println("產品A :part03() ..."); } } class ConcreteProductB extends AbstractProduct{ protected void part01() { System.out.println("產品B :part01() ..."); } protected void part02() { System.out.println("產品B :part02() ..."); } protected void part03() { System.out.println("產品B :part03() ..."); } } //抽象建造者,制定每一種產品應該實現的組合方式buildPart()和生產buildProduct()的標準 abstract class AbstractBuilder{ public abstract void buildPart(); public abstract AbstractProduct buildProduct(); } /* * 具體建造者,如果對於預設產品(即當調用抽象產品中的defaultProduct()方法)不滿意時, * 可以不調用它來獲得產品,而是使用具體的建造者來改變產品的生產組裝方式,以得到不同的產品 */ class ConcreteBuilderA extends AbstractBuilder{ private AbstractProduct productA = new ConcreteProductA(); public void buildPart() { this.productA.part03(); this.productA.part02(); this.productA.part01(); } public AbstractProduct buildProduct() { return this.productA; } } class ConcreteBuilderB extends AbstractBuilder{ private AbstractProduct productB = new ConcreteProductB(); public void buildPart() { this.productB.part02(); this.productB.part01(); //特地省略掉產品B中的一個組成部分,例如該部分的功能顧客不需要 // this.productB.part03(); } public AbstractProduct buildProduct() { return this.productB; } } //導演類,預先持有各個產品的建造者,為需要不同於預設產品的使用者提供不同的組裝方式 class Director{ private AbstractBuilder builderA = new ConcreteBuilderA(); private AbstractBuilder builderB = new ConcreteBuilderB(); public AbstractProduct getProductA() { this.builderA.buildPart(); return this.builderA.buildProduct(); } public AbstractProduct getProductB() { this.builderB.buildPart(); return this.builderB.buildProduct(); } } //測試類別 public class Client { public static void main(String[] args) { System.out.println("利用模板方法模式獲得預設的產品A"); AbstractProduct defualtProductA = new ConcreteProductA().defaultProduct(); System.out.println("\n利用Director類獲得不同組裝方式的產品A"); Director director = new Director(); director.getProductA(); System.out.println("\n利用Director類獲得不同組裝方式的產品B"); director.getProductB(); } }
測試結果:
利用模板方法模式獲得預設的產品A
產品A :part01() ...
產品A :part02() ...
產品A :part03() ...
利用Director類獲得不同組裝方式的產品A
產品A :part03() ...
產品A :part02() ...
產品A :part01() ...
利用Director類獲得不同組裝方式的產品B
產品B :part02() ...
產品B :part01() ...
其實在這個例子當中,產品類那一部分用到了上一篇文章講到的模板方法模式,即defaultProduct()提供了一個產品的預設組成部分的組裝方式。
但是這裡我有個疑問,AbstractProduct類中根據模板方法模式提供的的所謂預設組裝方式只是列印出幾句測試的話而已,又不是真正返回一個具體產品,但是上面例子中那樣返回一個當前對象(return this;)的處理方式不知道是否合理?
另外,在寫了這幾篇關於用Java代碼實現設計模式的文章之後,發現這個建造者Builder模式似乎是結合了抽象原廠模式、模板方法模式。上面一段已經說過我的疑惑,至於抽象原廠模式,我個人是覺得上面代碼例子中的Director類就很類似抽象工廠的具體工廠類了,但是Director類還要負責build一下產品的組裝方式才返回一個產品,也許就是這個“build一下”才顯得建造者模式關注於產品各個部分的組裝,而抽象原廠模式僅僅只是關注於一個最終產品的產生。
之前看過一句話說大概是說:電腦方面的任何一個問題如果難以解決,都可以通過增加一個中介層來處理。現在想了一下,好像Abstract Factory和Builder模式都是運用了這一“原理”來達到想要的效果。譬如Abstract Factory中有個抽象工廠類,Builder中有個Director類,說到底也就是封裝隱藏某些細節,並從實現和使用這兩者之間解耦出來吧。
我認為,一定要先理解了各個模式的關注點和適用情境之後才能更好地把握這些吧。
可能這幾個模式都是建立型的模式而且我沒有什麼實戰經驗才會使得我對於這些有點混淆了...不怕,在它們全部實現的過程中一點點思考,慢慢地運用到實際當中去應該就會逐漸明白的了。
以上就是本文的全部內容,希望對大家的學習有所啟發。