什么是建造者模式?
建造者模式允许用户在创建复杂对象时,分离开其部件与构造的细节,更加精细地控制对象的构造过程,使得两者解耦。
使用建造者模式的意义
一句话概括:建造者模式是为了达到方法、属性间的解耦,即创建属性、实现方法不需要感知其余的代码块逻辑。
适用场景:
- 类对象初始化时参数众多,且大多数参数是需要默认值的,允许用户选择是否装配到对象中。
- 类对象创建由于不同的方法调用顺序,而得到不同的结果时,就非常适合使用该模式了。
建造者模式的实现方式
以下为常见的实现方式,对于用户来说创建友好,内部实现解耦。定义一个动物类Animal,构建内部类Builder,允许输入体重weight,是否能跑canRun,是否能游泳canSwim,用户可以根据使用场景对Builder输入对应的参数。最终创建的Animal对象调用guessWhat方法,能返回Builder参数匹配上的"动物"。
public class Animal {
private Builder builder;
private Animal(Builder builder){
this.builder = builder;
}
public String guessWhat(){
// do anything ...
if(builder.canRun){
if(builder.weight <= 20){
return "橘猫";
}
} else if(builder.canSwim){
if(builder.weight > 100000){
return "鲸鱼";
}
}
return "未知";
}
public static class Builder{
int weight;
boolean canRun;
boolean canSwim;
public Builder setWeight(int weight) {
this.weight = weight;
return this;
}
public Builder setCanRun(boolean canRun) {
this.canRun = canRun;
return this;
}
public Builder setCanSwim(boolean canSwim) {
this.canSwim = canSwim;
return this;
}
public Animal build(){
return new Animal(this);
}
}
}
源码中经典的建造者模式
参考Android SDK源码中已有的实现AlertDialog ,站在巨人的肩膀上,做起事情来肯定事半功倍了。以下为核心代码,可以看到里面代码分别有以下特点:
- AlertDialog 实现满足MVC设计模式,它本身属于View层,而有一个Controller层AlertController,帮助它处理业务。
- 外部调用AlertDialog.Builder封装属性,当属性定义并且最后调用show(),实际上是把所有的属性、实现全部提交到AlertController,再用于界面显示。
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
protected AlertDialog(Context context) {
this(context, 0);
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
this(context, 0);
setCancelable(cancelable);
setOnCancelListener(cancelListener);
}
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 = AlertController.create(getContext(), this, getWindow());
}
public Button getButton(int whichButton) {
return mAlert.getButton(whichButton);
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
/** 省略无关代码 **/
public static class Builder {
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, ResourceId.ID_NULL));
}
public Builder(Context context, int themeResId) {
// 每一个AlertDialog.Builder创建都会新建一个AlertController.AlertParams用于后续提交到AlertDialog对象中的AlertController。
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
public Context getContext() {
return P.mContext;
}
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public AlertDialog create() {
// 创建AlertDialog对象,把Builder中AlertController P对象的实现提交到AlertDialog对象的AlertController中。
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
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;
}
}
}
总结
- 建造者模式有良好的封装性,用户不需要感知到它的构造过程。
- 建造过程中能很好达到方法级别的解耦,符合较好的代码原则。
- 但使用时相对的也是增加了对象的创建,消耗内存。