《Android源码设计模式解析与实战》读书笔记(三)

第三章、Builder模式

1.定义

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

2.使用场景

(1)相同的方法,不同的执行顺序,产生不同的事件结果时。
(2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
(3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个使用建造者模式非常适合。
(4)当初始化一个对象特别复杂时,如参数多,且很多参数有默认值。

3.简单实现

public interface Builder {

  //创建部件A  比如创建汽车车轮
  void buildPartA(); 
  //创建部件B 比如创建汽车方向盘
  void buildPartB(); 
  //创建部件C 比如创建汽车发动机
  void buildPartC();
  //返回最后组装成品结果 (返回最后装配好的汽车)
  Product getResult();

}
//Director 类,负责制造
public class Director {

  private Builder builder;

  public Director( Builder builder ) { 
    this.builder = builder; 
  } 
  // 将部件partA partB partC最后组成复杂对象
  //这里是将车轮 方向盘和发动机组装成汽车的过程
  public void construct() { 
    builder.buildPartA();
    builder.buildPartB();
    builder.buildPartC();

  }

}

public class ConcreteBuilder implements Builder {

  Part partA, partB, partC; 
  public void buildPartA() {
    //这里是具体如何构建partA的代码
  }; 
  public void buildPartB() { 
    //这里是具体如何构建partB的代码
  }; 
   public void buildPartC() { 
    //这里是具体如何构建partB的代码
  }; 
   public Product getResult() { 
    //返回最后组装成品结果
  }; 
}

public interface Product { }//产品

public interface Part { }//部件

//调用
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder ); 

director.construct(); 
Product product = builder.getResult();

从上面可以看到由于Director封装了构建复杂的产品对象过程,对外隐藏了细节。

现实开发中,Director一般被省略。而直接使用一个Builder来进行对象的组装,这个Builder通常为链式调用,他是将setter方法返回自身。代码大致如下:

new TestBuilder().setA("A").setB("B").create();

4.Android源码中的Builder模式

1.AlertDialog.Builder

源码太长截取部分:

public static class Builder {
        private final AlertController.AlertParams P;
        private int mTheme;

        /** * Constructor using a context for this builder and the {@link AlertDialog} it creates. */
        public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }

        /** * Constructor using a context and theme for this builder and * the {@link AlertDialog} it creates. The actual theme * that an AlertDialog uses is a private implementation, however you can * here supply either the name of an attribute in the theme from which * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme} * or one of the constants * {@link AlertDialog#THEME_TRADITIONAL AlertDialog.THEME_TRADITIONAL}, * {@link AlertDialog#THEME_HOLO_DARK AlertDialog.THEME_HOLO_DARK}, or * {@link AlertDialog#THEME_HOLO_LIGHT AlertDialog.THEME_HOLO_LIGHT}. */
        public Builder(Context context, int theme) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, theme)));
            mTheme = theme;
        }

        /** * Returns a {@link Context} with the appropriate theme for dialogs created by this Builder. * Applications should use this Context for obtaining LayoutInflaters for inflating views * that will be used in the resulting dialogs, as it will cause views to be inflated with * the correct theme. * * @return A Context for built Dialogs. */
        public Context getContext() {
            return P.mContext;
        }

        /** * Set the title displayed in the {@link Dialog}. * * @return This Builder object to allow for chaining of calls to set methods */
        public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;//**这里返回自身,类似的来设置各种参数。
        }
       // ......省略
          /** * Creates a {@link AlertDialog} with the arguments supplied to this builder. It does not * {@link Dialog#show()} the dialog. This allows the user to do any extra processing * before displaying the dialog. Use {@link #show()} if you don't have any other processing * to do and want this to be created and displayed. */
        public AlertDialog create() {
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
            P.apply(dialog.mAlert);//将P中的参数应用到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;
        }

        /** * Creates a {@link AlertDialog} with the arguments supplied to this builder and * {@link Dialog#show()}'s the dialog. */
        public AlertDialog show() {
            AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }
    }

上面有个AlertController.AlertParams 的成员参数P,我们在Builder设置的title,icon等都储存在他里面。在调用create时在P.apply使用。

5.总结

优点:

(1)良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成细节。
(2)建造者独立,容易扩展。

缺点:

(1)会产生多余的Builder对象及Director对象,消耗内存。

6.参考

链接:设计模式之Builder

    原文作者:唯鹿
    原文地址: https://blog.csdn.net/qq_17766199/article/details/50250169
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞