建造者模式

建造者模式的定義

定義:將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。

通用類圖如下:

建造者通用類圖.png

角色說(shuō)明

  • Product產(chǎn)品類

    通常是實(shí)現(xiàn)了模板方法模式,也就是有模板方法和基本方法

  • Builder抽象建造者

    規(guī)范產(chǎn)品的組件,一般由子類實(shí)現(xiàn)。

  • ConcreteBuilder具體建造者

    實(shí)現(xiàn)抽象類定義的所有方法,并且返回一個(gè)組建好的對(duì)象。

  • Director導(dǎo)演類

    負(fù)責(zé)安排已有模塊的順序,然后告訴Builder開(kāi)始建造。

通用代碼

產(chǎn)品類

public class Product {
     public void doSomething(){
             //獨(dú)立業(yè)務(wù)處理
     }
}

抽象建造者

public abstract class Builder {
     //設(shè)置產(chǎn)品的不同部分,以獲得不同的產(chǎn)品
     public abstract void setPart();
     //建造產(chǎn)品
     public abstract Product buildProduct();
}

具體建造者

public class ConcreteProductBuilder extends Builder {
     private Product product = new Product();
     //設(shè)置產(chǎn)品零件
     public void setPart(){
             /*
              * 產(chǎn)品類內(nèi)的邏輯處理
              */
     }
     //組建一個(gè)產(chǎn)品
     public Product buildProduct() {
             return product;
     }
}

需要注意的是,如果有多個(gè)產(chǎn)品類就有幾個(gè)具體的建造者,而且這些產(chǎn)品類具有相同的接口或抽象類。

導(dǎo)演類

public class Director {
     private Builder builder = new ConcreteProductBuilder();
     //構(gòu)建不同的產(chǎn)品
     public Product getAProduct(){
             builder.setPart();
             /*
              * 設(shè)置不同的零件,產(chǎn)生不同的產(chǎn)品
              */
             return builder.buildProduct();
     }
}

導(dǎo)演類起到封裝作用,避免高層模塊深入到建造者內(nèi)部的實(shí)現(xiàn)類。當(dāng)然,在建造者模式比較龐大的時(shí)候,導(dǎo)演類也可以有多個(gè)。

示例

不同廠家的生產(chǎn)的汽車,它的動(dòng)作執(zhí)行順序要求不一樣,例如:第一個(gè)公司的車只要啟動(dòng)和停止功能,其他的什么都不要;第二個(gè)公司要求汽車啟動(dòng)時(shí),要先鳴喇叭,然后啟動(dòng),然后停止。。。

針對(duì)上面的情況,我們可以為每家公司的車定義一個(gè)建造者,你要功能順序直接告訴建造者,由建造者來(lái)建造

類圖如下:

汽車構(gòu)造類圖.png

CarModel類

public abstract class CarModel {
     //這個(gè)參數(shù)是各個(gè)基本方法執(zhí)行的順序
     private ArrayList<String> sequence = new ArrayList<String>();
     //模型是啟動(dòng)開(kāi)始跑了
     protected abstract void start();
     //能發(fā)動(dòng),還要能停下來(lái),那才是真本事
     protected abstract void stop();
     //喇叭會(huì)出聲音,是滴滴叫,還是嗶嗶叫
     protected abstract void alarm();
     //引擎會(huì)轟隆隆地響,不響那是假的
     protected abstract void engineBoom();
     //那模型應(yīng)該會(huì)跑吧,別管是人推的,還是電力驅(qū)動(dòng),總之要會(huì)跑
     final public void run() {
             //循環(huán)一邊,誰(shuí)在前,就先執(zhí)行誰(shuí)
             for(int i=0;i<this.sequence.size();i++){
                      String actionName = this.sequence.get(i);
                      if(actionName.equalsIgnoreCase("start")){
                              this.start();  //啟動(dòng)汽車
                      }else if(actionName.equalsIgnoreCase("stop")){
                              this.stop(); //停止汽車
                      }else if(actionName.equalsIgnoreCase("alarm")){
                              this.alarm(); //喇叭開(kāi)始叫了
                       }else if(actionName.equalsIgnoreCase("engine boom")){
                                                            //如果是engine boom關(guān)鍵字
                              this.engineBoom();  //引擎開(kāi)始轟鳴
                       }
             }
     }
     //把傳遞過(guò)來(lái)的值傳遞到類內(nèi)
     final public void setSequence(ArrayList sequence){
             this.sequence = sequence;
     }
}

奔馳和寶馬的模型

public class BenzModel extends CarModel {
     protected void alarm() {
             System.out.println("奔馳車的喇叭聲音是這個(gè)樣子的...");
     }
     protected void engineBoom() {
             System.out.println("奔馳車的引擎是這個(gè)聲音的...");
     }
     protected void start() {
             System.out.println("奔馳車跑起來(lái)是這個(gè)樣子的...");
     }
     protected void stop() {
             System.out.println("奔馳車應(yīng)該這樣停車...");
     }
}

public class BMWModel extends CarModel {
     protected void alarm() {
             System.out.println("寶馬車的喇叭聲音是這個(gè)樣子的...");
     }
     protected void engineBoom() {
             System.out.println("寶馬車的引擎是這個(gè)聲音的...");
     }
     protected void start() {
             System.out.println("寶馬車跑起來(lái)是這個(gè)樣子的...");
     }
     protected void stop() {
             System.out.println("寶馬車應(yīng)該這樣停車...");
     }
}

汽車抽象構(gòu)造者

public abstract class CarBuilder {
     //建造一個(gè)模型,你要給我一個(gè)順序要求,就是組裝順序
     public abstract void setSequence(ArrayList<String> sequence);
     //設(shè)置完畢順序后,就可以直接拿到這個(gè)車輛模型
     public abstract CarModel getCarModel();
}

奔馳車的組裝者

public class BenzBuilder extends CarBuilder {
     private BenzModel benz = new BenzModel();
     public CarModel getCarModel() {
             return this.benz;
     }
     public void setSequence(ArrayList<String> sequence) {
             this.benz.setSequence(sequence);
     }
}

寶馬車的組裝者與上面類似

導(dǎo)演者類

public class Director {
     private ArrayList<String> sequence = new ArrayList();
     private BenzBuilder benzBuilder = new BenzBuilder();
     private BMWBuilder bmwBuilder = new BMWBuilder();
     /*
      * A類型的奔馳車模型,先start,然后stop,其他什么引擎、喇叭一概沒(méi)有
      */
     public BenzModel getABenzModel(){
             //清理場(chǎng)景
             this.sequence.clear();
             //ABenzModel的執(zhí)行順序
             this.sequence.add("start");
             this.sequence.add("stop");
             //按照順序返回一個(gè)奔馳車
             this.benzBuilder.setSequence(this.sequence);
             return (BenzModel)this.benzBuilder.getCarModel();
     }
     /*
      * B型號(hào)的奔馳車模型,是先發(fā)動(dòng)引擎,然后啟動(dòng),然后停止,沒(méi)有喇叭
      */
     public BenzModel getBBenzModel(){
             this.sequence.clear();
             this.sequence.add("engine boom");
             this.sequence.add("start");
             this.sequence.add("stop");
             this.benzBuilder.setSequence(this.sequence);
             return (BenzModel)this.benzBuilder.getCarModel();
     }
     /*
      * C型號(hào)的寶馬車是先按下喇叭(炫耀嘛),然后啟動(dòng),然后停止
      */
     public BMWModel getCBMWModel(){
             this.sequence.clear();
             this.sequence.add("alarm");
             this.sequence.add("start");
             this.sequence.add("stop");
             this.bmwBuilder.setSequence(this.sequence);
             return (BMWModel)this.bmwBuilder.getCarModel();
     }
     /*
      * D類型的寶馬車只有一個(gè)功能,就是跑,啟動(dòng)起來(lái)就跑,永遠(yuǎn)不停止
      */
     public BMWModel getDBMWModel(){
             this.sequence.clear();
             this.sequence.add("start");
             this.bmwBuilder.setSequence(this.sequence);
             return (BMWModel)this.benzBuilder.getCarModel();
     }
     /*
      * 這里還可以有很多方法,你可以先停止,然后再啟動(dòng),或者一直停著不動(dòng),靜態(tài)的嘛
      * 導(dǎo)演類嘛,按照什么順序是導(dǎo)演說(shuō)了算
      */
}

this.sequence.clear()的作用是防止數(shù)據(jù)混亂,提前清空一下List。

具體場(chǎng)景類

public class Client {
     public static void main(String[] args) {
             Director director = new Director();
             //1萬(wàn)輛A類型的奔馳車
             for(int i=0;i<10000;i++){
                     director.getABenzModel().run();
             }
             //100萬(wàn)輛B類型的奔馳車
             for(int i=0;i<1000000;i++){
                     director.getBBenzModel().run();
             }
             //1000萬(wàn)輛C類型的寶馬車
             for(int i=0;i<10000000;i++){
                     director.getCBMWModel().run();
             }
     }
}

建造者模式的應(yīng)用

優(yōu)點(diǎn)

  • 封裝性

    使用建造者可以使客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)。

  • 建造者獨(dú)立,容易擴(kuò)展

    各Builder間相互獨(dú)立,對(duì)系統(tǒng)的擴(kuò)展非常有利。

  • 便于控制細(xì)節(jié)風(fēng)險(xiǎn)

    由于具體的建造者是獨(dú)立的,因此可以對(duì)建造者過(guò)程逐步細(xì)化,而不對(duì)其他的模塊產(chǎn)生任何影響。

使用場(chǎng)景

相同的方法,不同的執(zhí)行順序,產(chǎn)生不同的時(shí)間結(jié)果時(shí),可以采用建造者模式。

多個(gè)部件或零件,都可以裝配到一個(gè)對(duì)象中,但是產(chǎn)生的運(yùn)行結(jié)果又不相同,則可以使用該模式。

產(chǎn)品類非常復(fù)雜,或者產(chǎn)品類中的調(diào)用順序不同產(chǎn)生了不同的效能,這個(gè)時(shí)候使用建造者模式非常合適。

在對(duì)象創(chuàng)建過(guò)程中使用到系統(tǒng)中的一些其他對(duì)象,這些對(duì)象在產(chǎn)品對(duì)象的創(chuàng)建過(guò)程中不易得到時(shí),也可以采用建造者模式封裝該對(duì)象的創(chuàng)建過(guò)程。該中場(chǎng)景只能是一個(gè)補(bǔ)償方法,因?yàn)橐粋€(gè)對(duì)象不容易獲得,而在設(shè)計(jì)階段竟然沒(méi)有發(fā)覺(jué),而要通過(guò)創(chuàng)建者模式柔化創(chuàng)建過(guò)程,本身已經(jīng)違反設(shè)計(jì)的最初目標(biāo)。

注意事項(xiàng)

建造者模式關(guān)注的是零件類型和裝配工藝(順序),這是它與工廠方法最大不同的地方,雖然同為創(chuàng)建類模式,但是注重點(diǎn)不同。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容