Android常見設(shè)計(jì)模式十:Build模式

對于開發(fā)人員來說,設(shè)計(jì)模式有時(shí)候就是一道坎,但是設(shè)計(jì)模式又非常有用,過了這道坎,它可以讓你水平提高一個(gè)檔次。而在android開發(fā)中,必要的了解一些設(shè)計(jì)模式又是必須的,因?yàn)樵O(shè)計(jì)模式在Android源碼中,可以說是無處不在。對于想系統(tǒng)的學(xué)習(xí)設(shè)計(jì)模式的同學(xué),這里推薦一本書,《大話設(shè)計(jì)模式》。


Android常用設(shè)計(jì)模式系列:

面向?qū)ο蟮幕A(chǔ)特征
面向?qū)ο蟮脑O(shè)計(jì)原則
單例模式
模板模式
適配器模式
工廠模式
代理模式
原型模式
策略模式
Build模式
觀察者模式
裝飾者模式
中介模式
門面模式


Build模式

Build模式是非常常見的設(shè)計(jì)模式之一,寫個(gè)筆記,記錄一下我的學(xué)習(xí)過程和心得。

首先了解一些Build模式的定義。

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

但是看完這個(gè)定義,并沒有什么卵用,你依然不知道什么是Builder設(shè)計(jì)模式。在此個(gè)人的態(tài)度是學(xué)習(xí)設(shè)計(jì)模式這種東西,不要過度在意其定義,定義往往是比較抽象的,學(xué)習(xí)它最好的例子就是通過樣例代碼。

我們通過一個(gè)例子來引出Builder模式。假設(shè)有一個(gè)Car類,我們通過該Car類來構(gòu)建一大批汽車,這個(gè)Car類里有很多屬性,最常見的比如顏色,價(jià)格,品牌,排量等等,并且我們允許這些值不被設(shè)置,也就是允許為null,該類的定義如下。

public class Car  {
    Color color;
    double price;
    String brand;
    String displacement;

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

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

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getDisplacement() {
        return displacement;
    }

    public void setDisplacement(String displacement) {
        this.displacement = displacement;
    }
}

然后我們?yōu)榱朔奖憧赡軙x一個(gè)構(gòu)造方法。

public Car(Color color, double price, String brand, String displacement) {
 this.color = color;
 this.price = price;
 this.brand = brand;
 this. displacement = displacement;
}

有時(shí)候,只想傳部分參數(shù),你還會定義如下類似的構(gòu)造方法。

public Car(Color color) {
 this.color = color;
}
 public Car(Color color, double price) {
 this.color = color;
 this.price = price;
}
 public Car(Color color, double price, String brand) {
this.color = color;
 this.price = price;
 this.brand = brand;
} 

于是你就可以這樣創(chuàng)建各個(gè)需要的對象

Person p2=new Person(Color.read);
Person p3=new Person(Color.blue,180000);
Person p4=new Person(Color.green,21180, "小鵬");
Person p5=new Person(Color.white,17170,"法拉利","4.0L"); 

可以想象一下這樣創(chuàng)建的壞處,如果四個(gè)參都是同一種數(shù)據(jù)類型,那各個(gè)參數(shù)到底是什么意思,那得考讀性了,。還有一個(gè)問題就是當(dāng)有很多參數(shù)時(shí),編寫這個(gè)構(gòu)造數(shù)就會顯得異常麻煩,這時(shí)候如果換一個(gè)角度,試試Builder模式,你會發(fā)現(xiàn)代碼的可讀性一下子就上去了。

我們給Car增加一個(gè)靜態(tài)內(nèi)部類Builder類,并修改Car類的構(gòu)造函數(shù),代碼如下。

public class Car  {
    Color color;
    double price;
    String brand;
    String displacement;

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

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

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getDisplacement() {
        return displacement;
    }

    public void setDisplacement(String displacement) {
        this.displacement = displacement;
    }

    private Car(Builder builder) {
 this.color = builder.color;
 this.price = builder.price;
 this.brand = builder.brand;
 this. displacement = builder.displacement;
    }
    
    
    public static class Builder {

    Color color;
    double price;
    String brand;
    String displacement;
        
        public  Builder color(Color color){
            this.color=color;
            return  this;
        }
        public  Builder price(double price){
            this.price=price;
            return  this;
        }
        public  Builder brand(String brand){
            this.brand=brand;
            return  this;
        }
        public  Builder displacement(String displacement){
            this.displacement=displacement;
            return  this;
        }


        public Car build() {
            return new Car(this);
        }
    }
}

這樣,我們就不會被Car類構(gòu)造函數(shù)的各個(gè)入?yún)⒏愕孟±锖苛恕?br> 此外Builder類中的成員函數(shù)返回Builder對象自身,讓它支持鏈?zhǔn)秸{(diào)用,使代碼可讀性大大增強(qiáng)。于是我們就可以這樣創(chuàng)建Car類。

new Car.Builder().color(Color.BLUE)
                 .price(129800)
                 .pailiang("1.5T")
                 .brand("小鵬")
                 .build();

有沒有覺得創(chuàng)建過程一下子就變得那么清晰了。對應(yīng)的值是什么屬性一目了然,可讀性大大增強(qiáng)。

綜上,我們總結(jié)一下build模式的要點(diǎn):

1. 定義一個(gè)靜態(tài)內(nèi)部類Builder,內(nèi)部的成員變量和外部類一樣
2. Builder類通過一系列的方法用于成員變量的賦值,并返回當(dāng)前對象本身(this)
3. Builder類提供一個(gè)外部類的創(chuàng)建方法(build、create……),該方法內(nèi)部調(diào)用了外部類的一個(gè)私有構(gòu)造函數(shù),入?yún)⒕褪莾?nèi)部類Builder
4. 外部類提供一個(gè)私有構(gòu)造函數(shù)供內(nèi)部類調(diào)用,在該構(gòu)造函數(shù)中完成成員變量的賦值,取值為Builder對象中對應(yīng)的成變量的值

模式應(yīng)用廣泛

其實(shí)在Android中, Builder模式也是被大量的運(yùn)用。比如常見的對話框的創(chuàng)建

AlertDialog.Builder builder=new AlertDialog.Builder(this);
AlertDialog dialog=builder.setTitle("標(biāo)題")
 .setIcon(android.R.drawable.ic_dialog_alert)
 .setView(R.layout.myview)
 .setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 }
 })
 .setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 }
 })
 .create();
dialog.show(); 

而且,各個(gè)第三方框架也大量的運(yùn)用了Builder模式
如Gson中的GsonBuilder,代碼太長了,就不貼了,有興趣自己去看源碼,這里只貼出其Builder的使用方法。

GsonBuilder builder=new GsonBuilder();
Gson gson=builder.setPrettyPrinting()
 .disableHtmlEscaping()
 .generateNonExecutableJson()
 .serializeNulls()
 .create(); 

再看看著名的網(wǎng)絡(luò)請求框架OkHttp

Request.
Builder builder=new Request.Builder();
Request request=builder.addHeader("","")
 .url("")
 .post(body)
 .build();

總結(jié)

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

Builder模式通常作為配置類的構(gòu)建器將配置的構(gòu)建和表示分離開來,同時(shí)也是將配置從目標(biāo)類中隔離出來,避免作為過多的setter方法,并且隱藏內(nèi)部的細(xì)節(jié)。Builder模式比較常見的實(shí)現(xiàn)形式是通過鏈?zhǔn)秸{(diào)用,這樣使得代碼更加簡潔、易懂。

缺點(diǎn)

內(nèi)部類與外部類相互引用,可能會導(dǎo)致內(nèi)存消耗比較大,不過鑒于現(xiàn)在的手機(jī)內(nèi)存來講,這點(diǎn)幾乎影響不大。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容