Builder模式
我们知道建造者模式,是将对象的创建过程与它的表示相分离开来,使得同样的创建过程有着不同的表示.它允许用户在不知道产品内部的构建细节,可以精细的控制产品的产品的构造流程.
Builder模式的组成
产品类的抽象类
Builder抽象类以及具体的Builder
Director指挥者
这么说比较抽象,我们来看一看AlertDialog的源码就知道Builder模式是怎么实现的!
AlertDialog源码
看源码首先看入口,比如构造函数,使用时调用的方法.
protected AlertDialog(Context context, @StyleRes int themeResId) {
this(context, themeResId, true);
}
AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
createContextThemeWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
相互调用,里面有个mAlert(AlertController),他是干嘛用的?留个疑问!
接着看调用的方法
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setButton(int whichButton, CharSequence text, Message msg) {
mAlert.setButton(whichButton, text, null, msg);
}
都是通过mAlert来操作的
再来看Builder:
public static class Builder {
// 一样有个AlertController p变量
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int themeResId) {
// 创建了P
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
// 一些设置 将设置的东西存到了P里面
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setIcon(@DrawableRes int iconId) {
P.mIconId = iconId;
return this;
}
在看Create():
public AlertDialog create() {
............
// 创建了AlertDialog
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
P.apply(dialog.mAlert);
.................
看apply
public void apply(AlertController dialog) {
// 之前将设置的参数放到了P,作为AlertController的成员变量
// 然后将这些变量放到了AlertDialog的AlertController中
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));
}
...........................
*/
}
经过以上的步骤,Builder的东西都放到了AlertDialog的AlertController中.
看关键的一步show
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
public void show() {
// isSHow 省略
mCanceled = false;
if (!mCreated) {
//走onCreate
dispatchOnCreate(null);
}
// 走onStart()
onStart();
// 获取DecorView
mDecor = mWindow.getDecorView();
.........
//将DecorView添加到mWindowManager中
mWindowManager.addView(mDecor, l);
// 发送显示Dialog的消息
sendShowMessage();
}
从上面我们可以看到Dialog也有自己的生命周期,视图的构建我们看看onCreate()
// 果然是通过AlertController 来控制
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
public void installContent() {
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();
}
setupView();就是用来初始化AlertDialog的各个视图,这样AlertDialog就显示完毕了.
总结
从AlertDialog的Builder模式,我们并没有看到Director角色的出现,在经典的设计模式上做了一定的精简,灵活的运用了该模式.
应用
著名的图片加载库,Universal-Imge-Loader里面的初始化配置灵活的运用了该模式.
ImageLoaderConfig config = ImageLoaderConfig .Builder().set...set...(线程池数,默认图片,加载策略等)
ImageLoader.getInstance().init(config)
通过Builder模式,将ImageLoaderConfig的构造函数私有化,外部就不能访问内部属性,同时一些getter,setter就不会出现在用户的视野,用户仅仅能通过Builder来设置属性,内部通过apply(config)将builder设置的值赋给ImageLoaderConfig的各个属性.
这样就能将构建与表示相分离.
缺点
要说Builder模式的缺点的话就是产生了多余的Builder以及Director对象,消耗内存!