Java設(shè)計模式之-建造者模式(Builder)

關(guān)于建造者模式(或者又叫構(gòu)造者模式),我在網(wǎng)上看了很多文章。其中不乏很多人直接把建造者模式等同于builder構(gòu)造器。我想說這是兩種完全不同的層次和方向,一種是從系統(tǒng)設(shè)計層面考慮的設(shè)計模式,用于使整個系統(tǒng)構(gòu)件間解耦更加明顯,更易于擴展;另一種則是為了讓構(gòu)造器能適應(yīng)多個參數(shù)而出現(xiàn)的構(gòu)造函數(shù)變體。
這里不再對網(wǎng)上漫天的Builder構(gòu)造器進行解釋,只針對建造者模式進行討論。

建造者模式:將類的使用者與類的建造方式解耦,將類的使用者與類的建造者解耦。

當(dāng)然,上面這句話也是我個人對建造者模式的理解。建造者模式就是實現(xiàn)了三點之間的解耦:類的使用者、類的建造者、類的建造方式
我們先來看一下建造者模式的示意類圖:

建造者模式
  • Builder, 抽象建造者,定義了建造一個類(Product)需要實現(xiàn)的方法;
  • ConcreteBuilder,具體建造者,實現(xiàn)了抽象建造者定義的方法;
  • Product,產(chǎn)品,其實就是建造者需要建造的東西;
  • Director,其實它才是真正的類的建造者,上面所說的Builder,其實只是定義了類的建造方式,但是真正和類的使用者交互的是Director,它作為具體類的提供者,完成了建造的步驟。

OK, 我們現(xiàn)在來從上面說的兩個解耦進行后續(xù)的解釋。


將類的使用者與類的建造方式解耦

平常我們想進行一個類的構(gòu)造會怎么寫?一般來說我們先new一個實例出來,然后對各個變量進行set,最后做我們想做的事情。這里大家也可以換成直接在構(gòu)造函數(shù)里面?zhèn)魅雲(yún)?shù),大致意思是一樣的。

Foo foo = new Foo();
foo.setA(123);
foo.setB("abc");
foo.setC(new bar());
foo.doSomething();

但是這種做法,實際上將類的初始化和各項配置工作都移交給了類的使用者來做,大大增強了類的使用者和類的建造方式之間的耦合關(guān)系,類的使用者必須完全了解如何建造這個類才可以,否則便等不到一個功能完好的實例,更不要說正確地使用了。

OK,那如果說我現(xiàn)在有這樣一個產(chǎn)品類,會被別人使用到。我們先假設(shè)產(chǎn)品類是這個樣子:

public class Product {
    private String name;

    private BigDecimal price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

而我們存在多種建造這個產(chǎn)品的方式,但首先我們需要定義一個接口,用以確定產(chǎn)品的建造者需要做哪些工作:

public interface IProductBuilder {
    public void giveName();
    public void givePrice();
    public Product build();
}

而后我們有了兩個建造商品的類,一個生產(chǎn)高質(zhì)量商品,另一個生產(chǎn)普通商品:

public class HighQualityProductBuilder implements IProductBuilder{
    private Product product = new Product();;
    @Override
    public void giveName() {
        product.setName("A High Quality Product comes out!");
    }

    @Override
    public void givePrice() {
        product.setPrice(new BigDecimal("299.99"));
    }

    @Override
    public Product build() {
        giveName();
        givePrice();
        refine();
        return product;
    }

    private void refine(){
        System.out.println("Don't know how, but the product get refined!");
    }
}
public class NormalProductBuilder implements IProductBuilder {
    private Product product = new Product();;

    @Override
    public void giveName() {
        product.setName("Product with normal quality......");
    }

    @Override
    public void givePrice() {
        product.setPrice(new BigDecimal("1.59"));
    }

    @Override
    public Product build() {
        giveName();
        givePrice();
        return product;
    }
}

這個時候我們能夠看到,在Builder類中,我已經(jīng)將值賦給了product的域,并且在build()方法中實現(xiàn)了產(chǎn)品的裝配和建造過程。后面會提到,這其實是建造者模式的一大問題所在。

而后,我們在main方法中模擬使用該類,這樣其實就能夠?qū)崿F(xiàn)了將類的使用者與類的建造方式解耦這一目的:

    public static void main(String[] args){
        IProductBuilder builder = new HighQualityProductBuilder();
        Product product = builder.build();
    }

但是到此為止,我們做得還不夠。大家可以看到,在類圖中展示的Builder、ConcreteBuilder、和Product都已經(jīng)出現(xiàn)了,但是Director還遲遲不肯露面。下面我們就來說一下Director在整個建造者模式中的作用。


將類的使用者與類的建造者解耦

為了實現(xiàn)這一解耦目標(biāo),我們引入了Director這個參與者。它主要做的工作,就是封裝了Builder,然后直接和外界類的使用者進行交互:

public class Director {
    private IProductBuilder builder;
    public Director(IProductBuilder builder){
        this.builder = builder;
    }
    
    public Product construct(){
        return builder.build();
    }
}

而后我們在main方法中使用director來替代原來直接寫builder的方式:

    public static void main(String[] args){
        Director director = new Director(new NormalProductBuilder());
        Product product = director.construct();
    }

看到這里,很多人可能會罵我根本就不懂。這不還是寫死了NormalProductBuilder了么?不照樣是緊耦合了么?有什么意義?其實如果大家寫過一點Spring就能頓悟這里面的妙處,只要我在Director構(gòu)造時使用注入,并將其實現(xiàn)為一個Bean,就可以很輕松地將其進行解耦。由一個Director來作為選擇和管理Builder的入口,而通過注入的方式將使用者與后方隔離開來,這才是建造者模式真正強大的地方。

一大問題

另外我上面也說了,建造者模式的一大問題,就是它把類的建造過程寫死了,綁死了,寫成了一套流程化的代碼邏輯,不易更改。

所以說,建造者模式適用于不易變更的且構(gòu)建復(fù)雜的類的實例化場景,而對那些生成過程經(jīng)常改變的類,則不建議使用該模式,因為得到的收益可能遠比不上修改的成本。

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

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

  • 沒有人買車會只買一個輪胎或者方向盤,大家買的都是一輛包含輪胎、方向盤和發(fā)動機等多個部件的完整汽車。如何將這些部件組...
    justCode_閱讀 1,999評論 1 6
  • 定義 建造模式是對象的創(chuàng)建模式。建造模式可以將一個產(chǎn)品的內(nèi)部表象(internal representation)...
    步積閱讀 7,196評論 1 7
  • 模式定義 建造者模式:將一個復(fù)雜產(chǎn)品的創(chuàng)建與表示分離,使得同樣的創(chuàng)建過程可以創(chuàng)建不同的表示客戶端不用去關(guān)心產(chǎn)品對象...
    C_zx閱讀 575評論 1 5
  • 我們知道,生成站點地圖之后會利于搜索引擎蜘蛛對網(wǎng)站信息的結(jié)構(gòu)化收錄,大家都在用插件,插件能少一個就少一個。現(xiàn)在給出...
    Yephy閱讀 2,620評論 0 3
  • 我是一個和尚,在誦經(jīng)房里抄楞嚴(yán)經(jīng)。梵文的音,難以理解的字,不管理不理解,悟性天資的問題。 那天,一個朋友,...
    楊懿閱讀 335評論 0 0

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