Builder模式既构建者模式,可以一步一步地创建一个复杂的对象。记住是复杂的对象,简单的在使用构建者就冗余了。很多的开源项目中也都用到了Builder模式,比如Rtrofit , Glide ,Picasso RxJava 等等,安卓系统中用到的也很多,最典型的就是我的的AertDialog。他们的很大的一个特点就是链式调用。使我们的代码写起来既简单又爽快。而链式调用的关键就是每个setter方法都返回自身。
下面举个简单的例子
有一个对象Person
public class Person {
private String name;
private String sex;
private double height;
private String address;
private String phone;
private String email;
public Person(String name, String sex, double height, String address, String phone, String email) {
this.name = name;
this.sex = sex;
this.height = height;
this.address = address;
this.phone = phone;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
正常我们创建这个Person对象是
Person person = new Person("大海","男",175,"北京","18813137878","136@163.com");
上面的方法可以构建出Person对象,但是缺点也很明显,当Person中的参数有很多的时候,我们在构建的时候,根本不知道下面的参数是哪个,还得去类里面看一下构造参数,在返回来填写。
另外当我们的Person对象有各种各样的构造实现,每种构造需要的参数都不一样,那我们的实体类中就需要写各种的参数的构造方法,当我们构造对象的时候更加不容易知道我们需要填写的参数是神马。
当然我们也可以先构造没有参数的对象。在一个一个set参数,这样也很麻烦哦,写一堆person.set()……
然后看一下builder模式的构建方式
public class Person {
private String name;
private String sex;
private double height;
private String address;
private String phone;
private String email;
public static class Builder{
Person mPerson;
public Builder() {
mPerson = new Person();
}
public Builder name(String name){
mPerson.name = name;
return this;
}
public Builder sex(String sex){
mPerson.sex = sex;
return this;
}
public Builder height(double height){
mPerson.height = height;
return this;
}
public Builder address(String address){
mPerson.address = address;
return this;
}
public Builder phone(String phone){
mPerson.phone = phone;
return this;
}
public Builder email(String email){
mPerson.email = email;
return this;
}
public Person build(){
return mPerson;
}
}
}
构建上面的Person类我们就可以这样:
Person person = new Person.Builder()
.name("dahai")
.sex("man")
.address("beijing")
.height(175)
.phone("18813137878")
.email("136@163.com")
.build();
这样看起来非常清晰,而且我们可以想要几个参数就添加几个参数很方便。比直接set参数简单很多,比使用构造器灵活很多。所以说builder模式是用来一步一步构建复杂的对象的。
下面来了解下AertDialog构建者模式
正常开发中使用AertDialog 一般都是如下;
new AlertDialog.Builder(this)
.setIcon(ContextCompat.getDrawable(this,R.mipmap.ic_launcher))
.setTitle("弹窗标题")
.setMessage("弹窗内容")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create()
.show();
首先从类名(AlertDialog.Builder)就可以看出这是一个Builder模式。通过Builder对象来构建dialog的各个部分,我们可以根据自己的需要来添加部件,如上面的setTitle , setMessage等。
AlertDialog中的部分代码:
public class AlertDialog extends AppCompatDialog implements DialogInterface {
final AlertController mAlert;
static final int LAYOUT_HINT_NONE = 0;
static final int LAYOUT_HINT_SIDE = 1;
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);
}
public Button getButton(int whichButton) {
return mAlert.getButton(whichButton);
}
public ListView getListView() {
return mAlert.getListView();
}
@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);
}
public void setView(View view) {
mAlert.setView(view);
}
...... 省略各种set方法......
可以看到 AlertDialog中的set方法设置的参数 最终都保存在成员变量AlertController中。
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 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 Builder setCustomTitle(View customTitleView) {
P.mCustomTitleView = customTitleView;
return this;
}
public Builder setMessage(@StringRes int messageId) {
P.mMessage = P.mContext.getText(messageId);
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
...... 中间省略一堆set ......
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。我的所set的值都保存AlertController.AlertParams中。AlertController.AlertParams包含了与AlertDialog 视图中对应的成员变量,在调用Builder中的create()的时候,会创建AlertDialog 并通过P.apply(dialog.mAlert)将AlertController.AlertParams中的参数保存在AlertDialog的成员变量AlertController中,然后返回dialog。
标准的builder模式还有一层Director类来封装Builder,但是一般真实的开发中一边都省略Director,直接链式的调用会更加清晰简单。
平时的工作中,我们自己写一些工具类的时候,都可以使用builder模式,来使我们的工具类更加方便使用。