当一个对象内部具有很多个组成部分时,如果简单的通过构造器的方式去创建这个对象,则显得比较繁琐。一种情况是构造函数会接受很多个参数,一种是需要重载多个构造函数,或者是需要调用多次setter
方法。在这时候,建造者模式就显得聪明很多。
定义
将一个复杂对象的构建与它的表示分离,使用同样的构建过程可以创建不同的表示。
场景
当初始化的一个对象特别复杂时,譬如,参数特别多而且都具有默认值。这是使用建造者模式比较多的场景。当然,还包括:
- 一个类的一系列方法在不同的调用顺序下,会产生不同的结果
- 一个类调用不同参数的构造器产生的实例,某些方法最终运行的结果不同
特点
- 隐藏构造细节
- 特有的建造者类Builder
- 简洁的调用(部分有序的链式调用)
- 更好的扩展性和良好的封装性
重要角色
产品类:需要构建的实例所属的类型,可以使接口,也可以是类
Builder:构建者模式核心类,辅助生成产品类实例的工具类
组装类:实施组装产品对象细节的管理类(大部分时候,这个角色由Builder担任)
源码分析
这里借助安卓系统对话框AlertDialog
的构造过程进行说明。
protected AlertDialog(@NonNull Context context) {
this(context, 0);
}
/**
* Construct an AlertDialog that uses an explicit theme. The actual style
* that an AlertDialog uses is a private implementation, however you can
* here supply either the name of an attribute in the theme from which
* to get the dialog's style (such as {@link R.attr#alertDialogTheme}.
*/
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
的,所以外部无法通过new
关键字的形式创建AlertDialog
对象。
在实际使用过程中,是通过内部类Builder
来创建AlertDialog
实例的。
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog alertDialog = builder.setIcon(R.drawable.iv).setCancelable(false).create();
稍微看一下Builder
类的功能
public static class Builder {
private final AlertController.AlertParams P;
private final int mTheme;
public Builder(@NonNull Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(@NonNull Context context, @StyleRes int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
mTheme = themeResId;
}
@NonNull
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
类型的成员变量,
用来存储创建AlertDialog
的参数,在create
方法中,对AlertDialog
进行组装并返回组装对象。
在AlertDialog
类中,AlertDialog
扮演了产品类的角色,内部类Builder
扮演了建造者类和组装类的角色
总结
建造者模式的出发点是将复杂对象的构建过程和表示过程分离开来。通过中间建造者来实现对产品类的构建过程,这样可以避免使用大量的setter
方法,而且在使用过程中,一般会采用调用链实现,使得代码更加简洁、易懂。
建造者模式的优点还在于它良好的封装性以及扩展性。通过建造者构建实例,不需要去了解实例对象内部的构造细节;建造者本身是独立的,因此具有更好的可扩展性。当然额外的Builder
实例以及可能的组装者实例也是一种内存的浪费。