Design Pattern ——Builder

一、基础知识:先前学习建造者模式的时候,总是以这个UML图作为学习基础资料

 

 

 

然后总是要记住四个角色

  • 产品类:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量。在本类图中,产品类是一个具体的类,而非抽象类。实际编程中,产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成。
  • 抽象建造者:引入抽象建造者的目的,是为了将建造的具体过程交与它的子类来实现。这样更容易扩展。一般至少会有两个抽象方法,一个用来建造产品,一个是用来返回产品。
  • 建造者:实现抽象类的所有未实现的方法,具体来说一般是两项任务:组建产品;返回组建好的产品。
  • 导演类:负责调用适当的建造者来组建产品,导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。一般来说,导演类被用来封装程序中易变的部分。住四然后总是要记住四个角色

我们可以看到,建造者模式相对工厂方法模式,更加注重产品建造过程,个人认为这才是Builder的核心思想。

 

二、近日看了一些Builder的例子,再一次觉得设计模式很多时候是一种思想,而不是照搬UML图

例子1.

 1 public class User {
 2     private final String firstName; // required
 3     private final String lastName; // required
 4     private final int age; // optional
 5     private final String phone; // optional
 6     private final String address; // optional
 7      
 8     private User(UserBuilder builder) {
 9         this.firstName = builder.firstName;
10         this.lastName = builder.lastName;
11         this.age = builder.age;
12         this.phone = builder.phone;
13         this.address = builder.address;
14     }
15      
16     public String getFirstName() {
17         return firstName;
18     }
19      
20     public String getLastName() {
21         return lastName;
22     }
23      
24     public int getAge() {
25         return age;
26     }
27      
28     public String getPhone() {
29         return phone;
30     }
31      
32     public String getAddress() {
33         return address;
34     }
35      
36     public static class UserBuilder {
37         private final String firstName;
38         private final String lastName;
39         private int age;
40         private String phone;
41         private String address;
42          
43         public UserBuilder(String firstName, String lastName) {
44             this.firstName = firstName;
45             this.lastName = lastName;
46         }
47          
48         public UserBuilder age(int age) {
49             this.age = age;
50             return this;
51         }
52          
53         public UserBuilder phone(String phone) {
54             this.phone = phone;
55             return this;
56         }
57          
58         public UserBuilder address(String address) {
59             this.address = address;
60             return this;
61         }
62          
63         public User build() {
64             return new User(this);
65         }
66          
67     }
68 }

当我们试图创建一个user对象的时候

1 public User getUser() {
2     return new
3     User.UserBuilder('Jhon', 'Doe')
4     .age(30)
5     .phone('1234567')
6     .address('Fake address 1234')
7     .build();
8 }

优点如下:

  • User构造方法是私有的,这意味着该类不能在客户端代码里直接实例化。
  • User所有属性都是final类型的,在构造方法里面被赋值。只提供了getter方法。
  • builder类使用流式接口风格,让客户端代码阅读起来更容易(见getUser())。
  • builder类构造方法只接收必须属性,为了确保这些属性在构造方法里赋值,只有这些属性被定义成final类型。

另外还有一个例子:

AlertDialog

 1 public class AlertDialog extends Dialog implements DialogInterface {
 2 
 3     ...
 4 
 5     protected AlertDialog(Context context, int theme) {
 6     this(context, theme, true);
 7     }
 8 
 9     AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
10         super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);
11 
12         mWindow.alwaysReadCloseOnTouchAttr();
13         mAlert = new AlertController(getContext(), this, getWindow());
14     }
15 
16     protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
17         super(context, resolveDialogTheme(context, 0));
18         mWindow.alwaysReadCloseOnTouchAttr();
19         setCancelable(cancelable);
20         setOnCancelListener(cancelListener);
21         mAlert = new AlertController(context, this, getWindow());
22     }
23 
24     public static class Builder {
25         private final AlertController.AlertParams P;
26         private int mTheme;
27 
28 
29         public Builder(Context context) {
30             this(context, resolveDialogTheme(context, 0));
31         }
32 
33 
34         public Builder(Context context, int theme) {
35             P = new AlertController.AlertParams(new ContextThemeWrapper(
36                     context, resolveDialogTheme(context, theme)));
37             mTheme = theme;
38         }
39 
40 
41         public Builder setMessage(CharSequence message) {
42             P.mMessage = message;
43             return this;
44         }
45 
46         public AlertDialog create() {
47             final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
48             P.apply(dialog.mAlert);
49             dialog.setCancelable(P.mCancelable);
50             if (P.mCancelable) {
51                 dialog.setCanceledOnTouchOutside(true);
52             }
53             dialog.setOnCancelListener(P.mOnCancelListener);
54             dialog.setOnDismissListener(P.mOnDismissListener);
55             if (P.mOnKeyListener != null) {
56                 dialog.setOnKeyListener(P.mOnKeyListener);
57             }
58             return dialog;
59         }
60         ...
61     }
62 }

我们可以看到:AlertDialog的Build是一个静态内部类。AlertDialog设置的属性会暂时保存在Build类的成员变量P(AlertController.AlertParams)中。同时,我们注意到我们设置的属性(如setMessage()),它都回返回本身的AlertBuild对象,这样我们就可以不停地调用它设置的方法(流式接口风格)。

如果我们想获得这个AlertDialog。我们就需要调用建造者的create()方法,在create()方法里面它就会构造出一个Dialog实例,并且将我们刚才设置的属性全部赋给AlertDialog,最后返回AlertDialog的实例

 

三、总结

从上面的UserBuilder和AlertDialog的例子,我们可以做一些总结。Builder设计模式的适用点:

1.产品的属性较多

2.产品本身不可变——Build后,不建议修改产品。

3.产品属性中有部分非必须的属性。

 

以上三点恰好符合“注重产品创建过程”的Builder核心思想。

 

 

参考资料:

http://www.importnew.com/11506.html 建造者模式实践

http://my.oschina.net/weiCloudS/blog/392872?fromerr=AIX2qbD2 在Android中探秘建造者模式

 

posted @ 2015-12-03 17:08  xerrard  阅读(298)  评论(0编辑  收藏  举报