zoukankan      html  css  js  c++  java
  • 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中探秘建造者模式

  • 相关阅读:
    Linux
    Linux
    JavaScript
    JavaScript
    Linux
    不可不说的Java“锁”事
    RabbitMQ公共配置
    求一个数字的补码
    项目中Controller的全局异常处理类
    如何较方便给上百张数据库表添加表字段
  • 原文地址:https://www.cnblogs.com/xerrard/p/5021891.html
Copyright © 2011-2022 走看看