haohao

Android 设计模式之 Builder 模式

Markdown

平坦的路往往只能带你到平凡的地方

最近在研究 Clean 和 Unidirectional ( Android Flux )架构,回头放一个大招。
本文是 Android 设计模式的第二篇,接下来会陆续推出整个常用的设计模式系列。

Builder 模式

Builder 又名生成器模式,或建造(者)模式。它是一种对象构建模式,用于抽象复杂对象的构建过程,构造过程的不同实现方法可以构建出具有不同表示的对象。

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

模式结构

  • Product 产品,表示被构造的复杂对象。
  • Builder 抽象构建者,为创建一个 Product 对象的各个部件指定抽象方法(接口方法)。
  • ConcreteBuilder 具体构建者,实现 Builder 接口(抽象类)以及各个抽象方法。
  • Director 指挥者,构建实现(继承) Builder 接口(抽象类)的对象。



盗图

模式实现

我们以生产手机为例,当我们拿到一个手机产品通常比较关注它的品牌 (Brand) ,CPU 核心数目 (CPU Core),运行内存 (RAM) 以及操作系统 (OS)。

Product

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Phone {
private int mCPUCore = 1;
private int mRam = 1;
private String mOS = "Android";
private String mBrand = "Google";
public int getCPUCore() {
return mCPUCore;
}
public int getRAM() {
return mRam;
}
public String getOS() {
return mOS;
}
public String getBrand() {
return mBrand;
}
public void setCPUCore(int mCPUCore) {
this.mCPUCore = mCPUCore;
}
public void setRAM(int mRam) {
this.mRam = mRam;
}
public void setOS(String mOS) {
this.mOS = mOS;
}
public void setBrand(String mBrand) {
this.mBrand = mBrand;
}
@Override
public String toString() {
return "Brand : " + getBrand() +", CPUCore : " + getCPUCore() +
", RAM : " + getRAM() + ", OS : " + getOS();
}
}

Builder 抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public abstract class PhoneBuilder {
protected Phone mPhone;
public void createPhone() {
mPhone = new Phone();
}
public Phone getPhone() {
return mPhone;
}
public abstract void buildPhoneCpu();
public abstract void buildPhoneRam();
public abstract void buildPhoneOS();
}
```
#### ConcreteBuilder
XiaoMiPhoneBuilder
```java
public class XiaoMiPhoneBuilder extends PhoneBuilder {
public XiaoMiPhoneBuilder() {
createPhone();
mPhone.setBrand("XiaoMi");
}
@Override
public void buildPhoneCpu() {
mPhone.setCPUCore(4);
}
@Override
public void buildPhoneRam() {
mPhone.setRAM(4);
}
@Override
public void buildPhoneOS() {
mPhone.setOS("MIUI Android");
}
}

GooglePhoneBuilder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class GooglePhoneBuilder extends PhoneBuilder {
public GooglePhoneBuilder() {
createPhone();
mPhone.setBrand("Google");
}
@Override
public void buildPhoneCpu() {
mPhone.setCPUCore(8);
}
@Override
public void buildPhoneRam() {
mPhone.setRAM(6);
}
@Override
public void buildPhoneOS() {
mPhone.setOS("Android");
}
}

Director

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class PhoneDirector {
private PhoneBuilder mPhoneBuilder;
public PhoneDirector setPhoneBuilder(PhoneBuilder phoneBuilder) {
this.mPhoneBuilder = phoneBuilder;
return this;
}
public Phone getPhone() {
return mPhoneBuilder.getPhone();
}
public PhoneDirector constructPhone() {
mPhoneBuilder.buildPhoneCpu();
mPhoneBuilder.buildPhoneOS();
mPhoneBuilder.buildPhoneRam();
return this;
}
}

Sample

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class BuilderSample {
public static void main(String[] args) {
PhoneDirector phoneDirector = new PhoneDirector();
PhoneBuilder xiaomiphoneBuilder = new XiaoMiPhoneBuilder();
PhoneBuilder googlePhoneBuilder = new GooglePhoneBuilder();
Phone xiaoMiPhone = phoneDirector.setPhoneBuilder(xiaomiphoneBuilder)
.constructPhone()
.getPhone();
Phone googlePhone = phoneDirector.setPhoneBuilder(googlePhoneBuilder)
.constructPhone()
.getPhone();
System.out.println(xiaoMiPhone + "\n" + googlePhone);
}
}

Running

Brand : XiaoMi, CPUCore : 4, RAM : 4, OS : MIUI Android

Brand : Google, CPUCore : 8, RAM : 6, OS : Android

Android 中的实现

在 Android 开发中我们最常用到的实现 Builder 的类是 AlertDialog.Builder ,Builder 是AlertDialog 的静态内部类。基本用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon);
builder.setTitle("Title");
builder.setMessage("Message");
builder.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的 OK 按钮");
}
});
builder.setNeutralButton("Nothing",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的 Nothing 按钮");
}
});
builder.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的 Cancel 按钮");
}
});
builder.create().show();

我们看一下简化后的 AlertDialog 源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class AlertDialog extends Dialog implements DialogInterface {
// Controller, 接受 Builder 成员变量P中的各个参数
private AlertController mAlert;
// 构造函数
protected AlertDialog(Context context, int theme) {
this(context, theme, true);
}
// 构造 AlertDialog
AlertDialog(Context context, int theme, boolean createContextWrapper) {
super(context, resolveDialogTheme(context, theme), createContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
@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);
}
// Builder内部类
public static class Builder {
// 存储 AlertDialog 的各个参数, 例如 title , message , icon 等.
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
......
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setIcon(int iconId) {
P.mIconId = iconId;
return this;
}
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this;
}
public Builder setView(View view) {
P.mView = view;
P.mViewSpacingSpecified = false;
return this;
}
// 构建 AlertDialog, 传递参数
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
将P中的参数应用的dialog中的mAlert对象中
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
}
}

从源码中可以看到 AlertDialog.Builder 同时扮演了 Builder , ConcreteBuilder 以及 Director 三个角色,是 Builder 模式的简化版。

我们从 AlertDialog 的构建和使用中,可以体会到运用 Builder 模式带来的简介性和高度的可定制性。

Builder 模式的优点和缺点

优点

  • 使用简单,可扩展性强,封装良好;
  • 高度的可定制性,构造过程可精细化控制。

缺点

  • Builder 模式只适用于构建过程复杂的同一类 Product ,此外要考虑多余 Builder 和 Director 对象对内存的占用。


联系我

Wechat ID

公众号

生活不止于眼前的苟且, 还有诗和远方的田野