99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Android學(xué)習(xí)之構(gòu)建者(Builder)模式

發(fā)布時間:2016-11-11 22:38  回復(fù):0  查看:2422   最后回復(fù):2016-11-11 22:38  

最近在Android開發(fā)中,使用 Retrofit  OkHttp 框架的過程中發(fā)現(xiàn)創(chuàng)建相關(guān)對象時頻繁使用到了Builder模式,鏈?zhǔn)秸{(diào)用的方式讓代碼變得簡潔、易懂,但自己也只是知其然而不知其所以然,所以決定做個筆記加深下印象。

一、場景分析

在實際開發(fā)中,往往會遇到需要構(gòu)建一個復(fù)雜的對象的代碼,像這樣的:

public class User {

private String name; // 必傳

private String cardID; // 必傳

private int age; // 可選

private String address; // 可選

}

于是我們起手就是擼了一串這樣的代碼,譬如:

通過構(gòu)造函數(shù)的參數(shù)形式去寫一個實現(xiàn)類

User(String name);

User(String nameString cardID);

User(String nameString cardID,int age);

User(String nameString cardID,int age, String address);

又或者通過設(shè)置settergetter方法的形式寫一個實現(xiàn)類

public class User {

private String name; // 必傳

private String cardID; // 必傳

private int age; // 可選

private String address; // 可選

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getCardID() {

return cardID;

}

public void setCardID(String cardID) {

this.cardID = cardID;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

}

先說說這兩種方式的優(yōu)劣:

第一種在參數(shù)不多的情況下,是比較方便快捷的,一旦參數(shù)多了,代碼可讀性大大降低,并且難以維護(hù),對調(diào)用者來說也造成一定困惑;

第二種可讀性不錯,也易于維護(hù),但是這樣子做對象會產(chǎn)生不一致的狀態(tài),當(dāng)你想要傳入全部參數(shù)的時候,你必需將所有的setXX方法調(diào)用完成之后才行。然而一部分的調(diào)用者看到了這個對象后,以為這個對象已經(jīng)創(chuàng)建完畢,就直接使用了,其實User對象并沒有創(chuàng)建完成,另外,這個User對象也是可變的,不可變類所有好處都不復(fù)存在。

寫到這里真想為自己最近封裝的表單控件捏一把汗。。。所以有沒有更好地方式去實現(xiàn)它呢,那就是接下來要理解的Builder模式了。

二、定義

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

Builder模式屬于創(chuàng)建型,一步一步將一個復(fù)雜對象創(chuàng)建出來,允許用戶在不知道內(nèi)部構(gòu)建細(xì)節(jié)的情況下,可以更精細(xì)地控制對象的構(gòu)造流程。

三、Builder模式變種-鏈?zhǔn)秸{(diào)用

代碼實現(xiàn)

public class User {

private final String name; //必選

private final String cardID; //必選

private final int age; //可選

private final String address; //可選

private final String phone; //可選

private User(UserBuilder userBuilder){

this.name=userBuilder.name;

this.cardID=userBuilder.cardID;

this.age=userBuilder.age;

this.address=userBuilder.address;

this.phone=userBuilder.phone;

}

public String getName() {

return name;

}

public String getCardID() {

return cardID;

}

public int getAge() {

return age;

}

public String getAddress() {

return address;

}

public String getPhone() {

return phone;

}

public static class UserBuilder{

private final String name;

private final String cardID;

private int age;

private String address;

private String phone;

public UserBuilder(String name,String cardID){

this.name=name;

this.cardID=cardID;

}

public UserBuilder age(int age){

this.age=age;

return this;

}

public UserBuilder address(String address){

this.address=address;

return this;

}

public UserBuilder phone(String phone){

this.phone=phone;

return this;

}

public User build(){

return new User(this);

}

}

}

需要注意的點:

· User類的構(gòu)造方法是私有的,調(diào)用者不能直接創(chuàng)建User對象。

· User類的屬性都是不可變的。所有的屬性都添加了final修飾符,并且在構(gòu)造方法中設(shè)置了值。并且,對外只提供getters方法。

· Builder的內(nèi)部類構(gòu)造方法中只接收必傳的參數(shù),并且該必傳的參數(shù)使用了final修飾符。

調(diào)用方式

new User.UserBuilder("Jack","10086")

.age(25)

.address("GuangZhou")

.phone("13800138000")

.build();

相比起前面通過構(gòu)造函數(shù)和setter/getter方法兩種方式,可讀性更強(qiáng)。唯一可能存在的問題就是會產(chǎn)生多余的Builder對象,消耗內(nèi)存。然而大多數(shù)情況下我們的Builder內(nèi)部類使用的是靜態(tài)修飾的(static),所以這個問題也沒多大關(guān)系。

關(guān)于線程安全

Builder模式是非線程安全的,如果要在Builder內(nèi)部類中檢查一個參數(shù)的合法性,必需要在對象創(chuàng)建完成之后再檢查,

正確示例:

public User build() {

User user = new user(this);

if (user.getAge() > 120) {

throw new IllegalStateException(“Age out of range”); // 線程安全

}

return user;

}

錯誤示例:

public User build() {

if (age > 120) {

throw new IllegalStateException(“Age out of range”); // 非線程安全

}

return new User(this);

}

四、經(jīng)典Builder模式

UML類圖

Android學(xué)習(xí)之構(gòu)建者(Builder)模式

 

Product : 產(chǎn)品抽象類

Builder : 抽象Builder類,規(guī)范產(chǎn)品組建,一般是由子類實現(xiàn)具體的組建過程

ConcreteBuilder : 具體的Builder

Director : 統(tǒng)一組裝過程

Product角色

/**

用戶抽象類

*/public abstract class User {

protected String name;

protected String cardID;

protected int age;

protected String address;

public void setName(String name) {

this.name = name;

}

public abstract void setCardID();

public void setAge(int age) {

this.age = age;

}

public void setAddress(String address) {

this.address = address;

}

@Override

public String toString() {

return "User [name ="+name+",cardID="+cardID+",age="+age+"," +

"address="+address+"]";

}

}

具體的Product

/**

具體的Product角色 SysUser

*/

public class SysUser extends User {

public SysUser() {

}

@Override

public void setCardID() {

cardID="10086"; //設(shè)置默認(rèn)ID

}

}

抽象Builder

public abstract class Builder {

public abstract void buildName(String name);

public abstract void buildCardID();

public abstract void buildAge(int age);

public abstract void buildAddress(String address);

public abstract User create();

}

具體的Builder

public class AccountBuilder extends Builder{

private User user=new SysUser();

@Override

public void buildName(String name) {

user.setName(name);

}

@Override

public void buildCardID() {

user.setCardID();

}

@Override

public void buildAge(int age) {

user.setAge(age);

}

@Override

public void buildAddress(String address) {

user.setAddress(address);

}

@Override

public User create() {

return user;

}

}

Director角色,負(fù)責(zé)構(gòu)造User

public class Director {

Builder mBuilder =null;

public Director(Builder builder){

this.mBuilder =builder;

}

public void construct(String name,int age,String address){

mBuilder.buildName(name);

mBuilder.buildCardID();

mBuilder.buildAge(age);

mBuilder.buildAddress(address);

}

}

測試代碼

public class Test{

public static void main(String args){

//構(gòu)建器

Builder builder=new AccountBuilder();

//Director

Director director=new Director(builder);

//封裝構(gòu)建過程:Jack10086,25,GuangZhou

director.construct("Jack",25,"GuangZhou");

//打印結(jié)果

System.out.println("Info :" +builder.create().toString());

}

}

輸出結(jié)果

System.out: Info :User [name =Jack,cardID=10086,age=25,address=GuangZhou]

六、用到Builder模式的例子

· Android中的AlertDialog.Builder

private void showDialog(){

AlertDialog.Builder builder=new AlertDialog.Builder(context);

builder.setIcon(R.drawable.icon);

builder.setTitle("Title");

builder.setMessage("Message");

builder.setPositiveButton("Button1", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//TODO

}

});

builder.setNegativeButton("Button2", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//TODO

}

});

builder.create().show();

}

· OkHttpOkHttpClient的創(chuàng)建

OkHttpClient okHttpClient = new OkHttpClient.Builder()

.cache(getCache())

.addInterceptor(new HttpCacheInterceptor())

.addInterceptor(new LogInterceptor())

.addNetworkInterceptor(new HttpRequestInterceptor())

.build();

· RetrofitRetrofit對象的創(chuàng)建

Retrofit retrofit = new Retrofit.Builder()

.client(createOkHttp())

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

.baseUrl(BASE_URL)

.build();

可見在實際使用中,均省略掉了Director角色,在很多框架源碼中,涉及到Builder模式時,大多都不是經(jīng)典GOFBuilder模式,而是選擇了結(jié)構(gòu)更加簡單的后者。

七、優(yōu)缺點

優(yōu)點:

· 良好的封裝性,使得客戶端不需要知道產(chǎn)品內(nèi)部實現(xiàn)的細(xì)節(jié)

· 建造者獨立,擴(kuò)展性強(qiáng)

缺點:

· 產(chǎn)生多余的Builder對象、Director對象,消耗內(nèi)存

 

文章來源:CSDN

您還未登錄,請先登錄

熱門帖子

最新帖子

?