0%

设计模式读书笔记-建造者模式

定义

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。

使用场景

  1. 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量。
  2. 需要生成的产品对象的属性相互依赖,需要制定其生成顺序。
  3. 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入指挥者类,将创建过程封装在指挥者类,而不在建造者类和客户类。
  4. 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

建造者模式概述

结构图

Builder Pattern

实例

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
//具体产品类
public class Computer{
protected String mBoard;
protected String mDisplay;
protected String mOS;

public String getBoard(){
return mBoard;
}

public String setBoard(String board){
mBoard = board;
}

public String getDisplay(){
return mDisplay;
}

public String setDisplay(String display){
mDisplay = display;
}

public String getOS(){
return mOS;
}

public String setOS(String OS){
mOS = OS;
}
}


//抽象建造者
public abstract class ComputerBuilder{

private Computer computer = new Computer();

public abstract void buildBoard();
public abstract void buildDisplay();
public abstract void buildOS();

public Computer create(){
return computer;
}
}

//具体建造者
public class MacbookBuilder extends ComputerBuilder{

@Override
public void buildBoard(){
computer.setBoard("Intel");
}

@Override
public void buildDisplay(){
computer.setDisplay("Retina");
}

@Override
public void buildOS(){
computer.setOS("OS X 10.13");
}
}


//指挥者
public class Director{

public Computer construct(ComputerBuilder computerbuilder){
Computer computer;
computerbuilder.buildBoard();
computerbuilder.buildDisplay();
computerbuilder.buildOS();
computer = computerbuilder.create();
return computer;
}
}


public class Client{
public static void main(String[] args){
Direcotr director = new Director();
ComputerBuilder builder = new MacbookBuilder();

Computer computer;
computer = diretor.construct(builder);

System.out.println(computer.mBoard);
System.out.println(computer.mDisplay);
System.out.println(computer.mOS);
}
}

省略Director

在Android源码中,最常用到的Builder模式就是AlertDialog.Builder,使用该Builder来构建复杂的AlertDialog对象。从类名就可以看出这就是Builder模式,通过Builder对象组装Dialog的各个部分,如title、buttons、Message等,将Dialog的构造和表示分离,这里作简单分析。

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
public class AlertDialog extends Dialog implements DialogInterface{
//AlertController接受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 AlertControllor(getContext(), this, getWindow());

}


//实际上调用的是mAlert的setTitle方法
@Override
public void setTitle(CharSequence title){
super.setTitle(title);
mAlert.setTitle(title);
}

//实际上调用的是mAlert的setCustomTitle方法
public void setCustomTitle(View customTitleView){
mAlert.setTitle(customTitleView);
}


public void setMessage(CharSequence message){
mAlert.setMessage(message);
}

// 省略...


// Builder为AlertDialog的内部类
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, imt theme){
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDilalogTheme(context, theme)));
mTheme = theme;
}

//设置各种参数
public Builder setTitle(CharSequence title){
P.mTitle = title;
return this;
}

public Builder setMessage(CharSequence message){
P.message = message;
return this;
}

public Builder setView(View view){
P.mView = view;
P.mViewSpacingSecified = false;
return this;
}

//构建AlertDialog,传递参数
public AlertDilaog create(){

//调用new AlertDialog构造对象,并且将参数传递给个体AlertDialog
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);

//将P中的参数应用到dialog中的mAlert对象中
P.apply(dialog.mAlert);

dialog.setCancelable(P.mCancelable);
if(P.mCanelable){
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
if(P.mOnKeyListener != null){
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}

上述代码中,Builder类可以设置AlertDialog中的title,message,button等参数,这些参数存储在类型为AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了AlertDialog中的成员变量。调用Builder类的create()函数时会创建AlertDialog,并将Builder成员变量P保存的参数应用到AlertDialog的mAlert对象中,即apply()函数,接下来的apply(),show(),setupView()不再展开分析。

在AlertDialog的Builder模式中并没有Director角色的出现。这里的AlertDialog.Builder同时扮演了Builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。

钩子方法的引入

建造者模式除了逐步构建了一个复杂产品对象外,还可以通过Director类来更加精细地控制产品的创建过程,例如增加一类称之为钩子方法(Hook Method)的特殊方法来控制是否调用某个buildPartX()方法。

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
public abstract class ComputerBuilder{

private Computer computer = new Computer();

public abstract void buildBoard();
public abstract void buildDisplay();
public abstract void buildOS();

public boolean isRetina(){
return false;
}

public Computer create(){
return computer;
}
}


public class MacbookBuilder extends ComputerBuilder{


@Override
public void buildBoard(){
computer.setBoard("Intel");
}

@Override
public void buildDisplay(){
computer.setDisplay("Retina");
}

@Override
public void buildOS(){
computer.setOS("OS X 10.13");
}

@Override
public boolean isRetina(){
return true;
}
}


public class Director{

public Computer construct(ComputerBuilder computerbuilder){
Computer computer;
computerbuilder.buildBoard();
if(computerbuilder.isRetina){
computerbuilder.buildDisplay();
}
computerbuilder.buildOS();
computer = computerbuilder.create();
return computer;
}
}

建造者模式总结

优点

  1. 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
  2. 每一个具体建造者都相对独立,而与其他具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的新产品对象,符合开闭原则。
  3. 可以更精细地控制产品的创建过程。

缺点

  1. 建造者所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,就不适合使用建造者模式。
  2. 如果产品内部结构过于复杂,可能会定义过多的ConcreteBuilder类,消耗内存同时不易于维护。