建造者模式及在Andorid中的應用
阿新 • • 發佈:2019-01-02
1. 建造者模式概述
建造者模式(Builder Pattern):將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。建造者模式是一種物件建立型模式。
建造者模式一步一步建立一個複雜的物件,它允許使用者只通過指定複雜物件的型別和內容就可以構建它們,使用者不需要知道內部的具體構建細節。建造者模式結構如圖所示:
- Builder(抽象建造者):它為建立一個產品Product物件的各個部件指定抽象介面,在該介面中一般宣告兩類方法,一類方法是buildPartX(),它們用於建立複雜物件的各個部件;另一類方法是getResult(),它們用於返回複雜物件。Builder既可以是抽象類,也可以是介面。
- ConcreteBuilder(具體建造者):它實現了Builder介面,實現各個部件的具體構造和裝配方法,定義並明確它所建立的複雜物件,也可以提供一個方法返回建立好的複雜產品物件。
- Product(產品角色):它是被構建的複雜物件,包含多個組成部件,具體建造者建立該產品的內部表示並定義它的裝配過程。
- Director(指揮者):指揮者又稱為導演類,它負責安排複雜物件的建造次序,指揮者與抽象建造者之間存在關聯關係,可以在其construct()建造方法中呼叫建造者物件的部件構造與裝配方法,完成複雜物件的建造
產品角色是我們最終要建立的物件,一個產品裡面有很多組成部分,典型程式碼如下:
抽象建造者定義了產品的各個組建的建立方法,典型程式碼如下:
具體建造者繼承於抽象建造者並實現了具體的各個組建的建立方式,典型程式碼如下:
指揮者隔離了客戶和產品的建立過程,實際控制了產品的建立流程,典型程式碼如下:
對於客戶端而言,只需關心具體的建造者即可,一般情況下,客戶端類程式碼片段如下所示:
2. 建造者模式在Andorid的AlertDialog中的應用
平常我們基本是這樣使用AlertDialog的,程式碼如下:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("標題" );
builder.setMessage("確定提交嗎?");
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
為什麼我們不能直接new一個AlertDialog呢,檢視原始碼發現:
protected AlertDialog(@NonNull Context context) {
this(context, 0);
}
protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
super(context, resolveDialogTheme(context, themeResId));
mAlert = new AlertController(getContext(), this, getWindow());
}
protected AlertDialog(@NonNull Context context, boolean cancelable,
@Nullable OnCancelListener cancelListener) {
this(context, 0);
setCancelable(cancelable);
setOnCancelListener(cancelListener);
}
AlertDialog的構造方法全是protected的,只能通過AlertDilog.Builder.create()構建,檢視AlertDilog.Builder原始碼主要如下:
private final AlertController.AlertParams P;
private final int mTheme;
public Builder(@NonNull Context context, @StyleRes int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
mTheme = themeResId;
}
public Builder setTitle(@Nullable CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setCustomTitle(@Nullable View customTitleView) {
P.mCustomTitleView = customTitleView;
return this;
}
public Builder setMessage(@Nullable CharSequence message) {
P.mMessage = message;
return this;
}
......
public AlertDialog create() {
// We can't use Dialog's 3-arg constructor with the createThemeContextWrapper param,
// so we always have to re-set the theme
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
可以看出Builder相當於建造者角色,AlertController.AlertParams相當於產品角色,Builder提供的一系列set方法都是為了改變AlertController.AlertParams的屬性,在create()方法裡,第25行 p.apply(dialog.mAlert), 檢視apply方法原始碼如下:
public void apply(AlertController dialog) {
if (mCustomTitleView != null) {
dialog.setCustomTitle(mCustomTitleView);
} else {
if (mTitle != null) {
dialog.setTitle(mTitle);
}
if (mIcon != null) {
dialog.setIcon(mIcon);
}
if (mIconId != 0) {
dialog.setIcon(mIconId);
}
if (mIconAttrId != 0) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
if (mMessage != null) {
dialog.setMessage(mMessage);
}
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null);
}
if (mNegativeButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
mNegativeButtonListener, null);
}
if (mNeutralButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
mNeutralButtonListener, null);
}
// For a list, the client can either supply an array of items or an
// adapter or a cursor
if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
createListView(dialog);
}
if (mView != null) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
} else if (mViewLayoutResId != 0) {
dialog.setView(mViewLayoutResId);
}
/*
dialog.setCancelable(mCancelable);
dialog.setOnCancelListener(mOnCancelListener);
if (mOnKeyListener != null) {
dialog.setOnKeyListener(mOnKeyListener);
}
*/
}
apply方法主要將AlertParams的屬性通過AlertController重新設定一遍,AlertDialog的屬性實際上還是通過AlertController控制,檢視AlertDialog的set方法程式碼,主要如下:
final AlertController mAlert;
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setCustomTitle(View customTitleView) {
mAlert.setCustomTitle(customTitleView);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
可以看出,AlertDialog的屬性都是通過AlertController控制,客戶不知道具體的建立細節,都是通過AlertController構建,AlertDialog充當指揮者的角色。