對(duì)于開發(fā)人員來(lái)說(shuō),設(shè)計(jì)模式有時(shí)候就是一道坎,但是設(shè)計(jì)模式又非常有用,過(guò)了這道坎,它可以讓你水平提高一個(gè)檔次。而在android開發(fā)中,必要的了解一些設(shè)計(jì)模式又是必須的,因?yàn)樵O(shè)計(jì)模式在Android源碼中,可以說(shuō)是無(wú)處不在。對(duì)于想系統(tǒng)的學(xué)習(xí)設(shè)計(jì)模式的同學(xué),這里推薦一本書,《大話設(shè)計(jì)模式》。
Android常用設(shè)計(jì)模式系列:
面向?qū)ο蟮幕A(chǔ)特征
面向?qū)ο蟮脑O(shè)計(jì)原則
單例模式
模板模式
適配器模式
工廠模式
代理模式
原型模式
策略模式
Build模式
觀察者模式
裝飾者模式
中介模式
門面模式
Build模式
Build模式是非常常見(jiàn)的設(shè)計(jì)模式之一,寫個(gè)筆記,記錄一下我的學(xué)習(xí)過(guò)程和心得。
首先了解一些Build模式的定義。
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示
但是看完這個(gè)定義,并沒(méi)有什么卵用,你依然不知道什么是Builder設(shè)計(jì)模式。在此個(gè)人的態(tài)度是學(xué)習(xí)設(shè)計(jì)模式這種東西,不要過(guò)度在意其定義,定義往往是比較抽象的,學(xué)習(xí)它最好的例子就是通過(guò)樣例代碼。
我們通過(guò)一個(gè)例子來(lái)引出Builder模式。假設(shè)有一個(gè)Car類,我們通過(guò)該Car類來(lái)構(gòu)建一大批汽車,這個(gè)Car類里有很多屬性,最常見(jiàn)的比如顏色,價(jià)格,品牌,排量等等,并且我們?cè)试S這些值不被設(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)榱朔奖憧赡軙?huì)定義一個(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ù),你還會(huì)定義如下類似的構(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è)需要的對(duì)象
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è)問(wèn)題就是當(dāng)有很多參數(shù)時(shí),編寫這個(gè)構(gòu)造數(shù)就會(huì)顯得異常麻煩,這時(shí)候如果換一個(gè)角度,試試Builder模式,你會(huì)發(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);
}
}
}
這樣,我們就不會(huì)被Car類構(gòu)造函數(shù)的各個(gè)入?yún)⒏愕孟±锖苛恕?br> 此外Builder類中的成員函數(shù)返回Builder對(duì)象自身,讓它支持鏈?zhǔn)秸{(diào)用,使代碼可讀性大大增強(qiáng)。于是我們就可以這樣創(chuàng)建Car類。
new Car.Builder().color(Color.BLUE)
.price(129800)
.pailiang("1.5T")
.brand("小鵬")
.build();
有沒(méi)有覺(jué)得創(chuàng)建過(guò)程一下子就變得那么清晰了。對(duì)應(yīng)的值是什么屬性一目了然,可讀性大大增強(qiáng)。
綜上,我們總結(jié)一下build模式的要點(diǎn):
1. 定義一個(gè)靜態(tài)內(nèi)部類Builder,內(nèi)部的成員變量和外部類一樣
2. Builder類通過(guò)一系列的方法用于成員變量的賦值,并返回當(dāng)前對(duì)象本身(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對(duì)象中對(duì)應(yīng)的成變量的值
模式應(yīng)用廣泛
其實(shí)在Android中, Builder模式也是被大量的運(yùn)用。比如常見(jiàn)的對(duì)話框的創(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,代碼太長(zhǎng)了,就不貼了,有興趣自己去看源碼,這里只貼出其Builder的使用方法。
GsonBuilder builder=new GsonBuilder();
Gson gson=builder.setPrettyPrinting()
.disableHtmlEscaping()
.generateNonExecutableJson()
.serializeNulls()
.create();
再看看著名的網(wǎng)絡(luò)請(qǐng)求框架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)建和表示分離開來(lái),同時(shí)也是將配置從目標(biāo)類中隔離出來(lái),避免作為過(guò)多的setter方法,并且隱藏內(nèi)部的細(xì)節(jié)。Builder模式比較常見(jiàn)的實(shí)現(xiàn)形式是通過(guò)鏈?zhǔn)秸{(diào)用,這樣使得代碼更加簡(jiǎn)潔、易懂。
缺點(diǎn)
內(nèi)部類與外部類相互引用,可能會(huì)導(dǎo)致內(nèi)存消耗比較大,不過(guò)鑒于現(xiàn)在的手機(jī)內(nèi)存來(lái)講,這點(diǎn)幾乎影響不大。