• Android源码分析之Builder模式


    模式的定义

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


    使用场景

    1、相同的方法,不同的执行顺序,产生不同的事件结果时;

    2、多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时;

    3、产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适;


    UML类图



    角色介绍

    Product 产品类 :  产品的抽象类。

    Builder : 抽象类, 规范产品的组建,一般是由子类实现具体的组件过程。

    ConcreteBuilder : 具体的构建器.

    Director : 统一组装过程(可省略)。


    简单示例

    下面我们以组装电脑为例来演示一下简单且经典的builder模式。

     

    [java] view plain copy
     
    1. package com.dp.example.builder;  
    2.   
    3. /** 
    4.  * Computer产品抽象类, 为了例子简单, 只列出这几个属性 
    5.  *  
    6.  * @author mrsimple 
    7.  * 
    8.  */  
    9. public abstract class Computer {  
    10.   
    11.     protected int mCpuCore = 1;  
    12.     protected int mRamSize = 0;  
    13.     protected String mOs = "Dos";  
    14.   
    15.     protected Computer() {  
    16.   
    17.     }  
    18.   
    19.     // 设置CPU核心数  
    20.     public abstract void setCPU(int core);  
    21.   
    22.     // 设置内存  
    23.     public abstract void setRAM(int gb);  
    24.   
    25.     // 设置操作系统  
    26.     public abstract void setOs(String os);  
    27.   
    28.     @Override  
    29.     public String toString() {  
    30.         return "Computer [mCpuCore=" + mCpuCore + ", mRamSize=" + mRamSize  
    31.                 + ", mOs=" + mOs + "]";  
    32.     }  
    33.   
    34. }  
    35.   
    36. package com.dp.example.builder;  
    37.   
    38. /** 
    39.  * Apple电脑 
    40.  * @author mrsimple 
    41.  * 
    42.  */  
    43. public class AppleComputer extends Computer {  
    44.   
    45.     protected AppleComputer() {  
    46.   
    47.     }  
    48.   
    49.     @Override  
    50.     public void setCPU(int core) {  
    51.         mCpuCore = core;  
    52.     }  
    53.   
    54.     @Override  
    55.     public void setRAM(int gb) {  
    56.         mRamSize = gb;  
    57.     }  
    58.   
    59.     @Override  
    60.     public void setOs(String os) {  
    61.         mOs = os;  
    62.     }  
    63.   
    64. }  
    65.   
    66. package com.dp.example.builder;  
    67.   
    68. /** 
    69.  * builder抽象类 
    70.  *  
    71.  * @author mrsimple 
    72.  * 
    73.  */  
    74. public abstract class Builder {  
    75.     // 设置CPU核心数  
    76.     public abstract void buildCPU(int core);  
    77.   
    78.     // 设置内存  
    79.     public abstract void buildRAM(int gb);  
    80.   
    81.     // 设置操作系统  
    82.     public abstract void buildOs(String os);  
    83.   
    84.     // 创建Computer  
    85.     public abstract Computer create();  
    86.   
    87. }  
    88.   
    89. package com.dp.example.builder;  
    90.   
    91. /** 
    92.  * Apple电脑 
    93.  * @author mrsimple 
    94.  * 
    95.  */  
    96. public class AppleComputer extends Computer {  
    97.   
    98.     protected AppleComputer() {  
    99.   
    100.     }  
    101.   
    102.     @Override  
    103.     public void setCPU(int core) {  
    104.         mCpuCore = core;  
    105.     }  
    106.   
    107.     @Override  
    108.     public void setRAM(int gb) {  
    109.         mRamSize = gb;  
    110.     }  
    111.   
    112.     @Override  
    113.     public void setOs(String os) {  
    114.         mOs = os;  
    115.     }  
    116.   
    117. }  
    118.   
    119. package com.dp.example.builder;  
    120.   
    121. /** 
    122.  * builder抽象类 
    123.  *  
    124.  * @author mrsimple 
    125.  * 
    126.  */  
    127. public abstract class Builder {  
    128.     // 设置CPU核心数  
    129.     public abstract void buildCPU(int core);  
    130.   
    131.     // 设置内存  
    132.     public abstract void buildRAM(int gb);  
    133.   
    134.     // 设置操作系统  
    135.     public abstract void buildOs(String os);  
    136.   
    137.     // 创建Computer  
    138.     public abstract Computer create();  
    139.   
    140. }  
    141.   
    142. package com.dp.example.builder;  
    143.   
    144. public class ApplePCBuilder extends Builder {  
    145.     private Computer mApplePc = new AppleComputer();  
    146.   
    147.     @Override  
    148.     public void buildCPU(int core) {  
    149.         mApplePc.setCPU(core);  
    150.     }  
    151.   
    152.     @Override  
    153.     public void buildRAM(int gb) {  
    154.         mApplePc.setRAM(gb);  
    155.     }  
    156.   
    157.     @Override  
    158.     public void buildOs(String os) {  
    159.         mApplePc.setOs(os);  
    160.     }  
    161.   
    162.     @Override  
    163.     public Computer create() {  
    164.         return mApplePc;  
    165.     }  
    166.   
    167. }  
    168.   
    169. package com.dp.example.builder;  
    170.   
    171. public class Director {  
    172.     Builder mBuilder = null;  
    173.   
    174.     /** 
    175.      *  
    176.      * @param builder 
    177.      */  
    178.     public Director(Builder builder) {  
    179.         mBuilder = builder;  
    180.     }  
    181.   
    182.     /** 
    183.      * 构建对象 
    184.      *  
    185.      * @param cpu 
    186.      * @param ram 
    187.      * @param os 
    188.      */  
    189.     public void construct(int cpu, int ram, String os) {  
    190.         mBuilder.buildCPU(cpu);  
    191.         mBuilder.buildRAM(ram);  
    192.         mBuilder.buildOs(os);  
    193.     }  
    194. }  
    195.   
    196. /** 
    197.  * 经典实现较为繁琐 
    198.  *  
    199.  * @author mrsimple 
    200.  * 
    201.  */  
    202. public class Test {  
    203.     public static void main(String[] args) {  
    204.         // 构建器  
    205.         Builder builder = new ApplePCBuilder();  
    206.         // Director  
    207.         Director pcDirector = new Director(builder);  
    208.         // 封装构建过程, 4核, 内存2GB, Mac系统  
    209.         pcDirector.construct(42"Mac OS X 10.9.1");  
    210.         // 构建电脑, 输出相关信息  
    211.         System.out.println("Computer Info : " + builder.create().toString());  
    212.     }  
    213. }  

    通过Builder来构建产品对象, 而Director封装了构建复杂产品对象对象的过程,但实现也比较为繁琐。

     


    源码分析

    Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象。简单示例如下 : 

     

    1.     //显示基本的AlertDialog  
    2.     private void showDialog(Context context) {  
    3.         AlertDialog.Builder builder = new AlertDialog.Builder(context);  
    4.         builder.setIcon(R.drawable.icon);  
    5.         builder.setTitle("Title");  
    6.         builder.setMessage("Message");  
    7.         builder.setPositiveButton("Button1",  
    8.                 new DialogInterface.OnClickListener() {  
    9.                     public void onClick(DialogInterface dialog, int whichButton) {  
    10.                         setTitle("点击了对话框上的Button1");  
    11.                     }  
    12.                 });  
    13.         builder.setNeutralButton("Button2",  
    14.                 new DialogInterface.OnClickListener() {  
    15.                     public void onClick(DialogInterface dialog, int whichButton) {  
    16.                         setTitle("点击了对话框上的Button2");  
    17.                     }  
    18.                 });  
    19.         builder.setNegativeButton("Button3",  
    20.                 new DialogInterface.OnClickListener() {  
    21.                     public void onClick(DialogInterface dialog, int whichButton) {  
    22.                         setTitle("点击了对话框上的Button3");  
    23.                     }  
    24.                 });  
    25.         builder.create().show();  // 构建AlertDialog, 并且显示
    26.     } 

    结果如图所示 :

     


    下面我们看看AlertDialog的部分源码 : 

     

    [java] view plain copy
     
    1. // AlertDialog  
    2. public class AlertDialog extends Dialog implements DialogInterface {  
    3.     // Controller, 接受Builder成员变量P中的各个参数  
    4.     private AlertController mAlert;  
    5.   
    6.     // 构造函数  
    7.     protected AlertDialog(Context context, int theme) {  
    8.         this(context, theme, true);  
    9.     }  
    10.   
    11.     // 4 : 构造AlertDialog  
    12.     AlertDialog(Context context, int theme, boolean createContextWrapper) {  
    13.         super(context, resolveDialogTheme(context, theme), createContextWrapper);  
    14.         mWindow.alwaysReadCloseOnTouchAttr();  
    15.         mAlert = new AlertController(getContext(), this, getWindow());  
    16.     }  
    17.   
    18.     // 实际上调用的是mAlert的setTitle方法  
    19.     @Override  
    20.     public void setTitle(CharSequence title) {  
    21.         super.setTitle(title);  
    22.         mAlert.setTitle(title);  
    23.     }  
    24.   
    25.     // 实际上调用的是mAlert的setCustomTitle方法  
    26.     public void setCustomTitle(View customTitleView) {  
    27.         mAlert.setCustomTitle(customTitleView);  
    28.     }  
    29.       
    30.     public void setMessage(CharSequence message) {  
    31.         mAlert.setMessage(message);  
    32.     }  
    33.   
    34.     // AlertDialog其他的代码省略  
    35.       
    36.     // ************  Builder为AlertDialog的内部类   *******************  
    37.     public static class Builder {  
    38.         // 1 : 存储AlertDialog的各个参数, 例如title, message, icon等.  
    39.         private final AlertController.AlertParams P;  
    40.         // 属性省略  
    41.           
    42.         /** 
    43.          * Constructor using a context for this builder and the {@link AlertDialog} it creates. 
    44.          */  
    45.         public Builder(Context context) {  
    46.             this(context, resolveDialogTheme(context, 0));  
    47.         }  
    48.   
    49.   
    50.         public Builder(Context context, int theme) {  
    51.             P = new AlertController.AlertParams(new ContextThemeWrapper(  
    52.                     context, resolveDialogTheme(context, theme)));  
    53.             mTheme = theme;  
    54.         }  
    55.           
    56.         // Builder的其他代码省略 ......  
    57.   
    58.         // 2 : 设置各种参数  
    59.         public Builder setTitle(CharSequence title) {  
    60.             P.mTitle = title;  
    61.             return this;  
    62.         }  
    63.           
    64.           
    65.         public Builder setMessage(CharSequence message) {  
    66.             P.mMessage = message;  
    67.             return this;  
    68.         }  
    69.   
    70.         public Builder setIcon(int iconId) {  
    71.             P.mIconId = iconId;  
    72.             return this;  
    73.         }  
    74.           
    75.         public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {  
    76.             P.mPositiveButtonText = text;  
    77.             P.mPositiveButtonListener = listener;  
    78.             return this;  
    79.         }  
    80.           
    81.           
    82.         public Builder setView(View view) {  
    83.             P.mView = view;  
    84.             P.mViewSpacingSpecified = false;  
    85.             return this;  
    86.         }  
    87.           
    88.         // 3 : 构建AlertDialog, 传递参数  
    89.         public AlertDialog create() {  
    90.             // 调用new AlertDialog构造对象, 并且将参数传递个体AlertDialog   
    91.             final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);  
    92.             // 5 : 将P中的参数应用的dialog中的mAlert对象中  
    93.             P.apply(dialog.mAlert);  
    94.             dialog.setCancelable(P.mCancelable);  
    95.             if (P.mCancelable) {  
    96.                 dialog.setCanceledOnTouchOutside(true);  
    97.             }  
    98.             dialog.setOnCancelListener(P.mOnCancelListener);  
    99.             if (P.mOnKeyListener != null) {  
    100.                 dialog.setOnKeyListener(P.mOnKeyListener);  
    101.             }  
    102.             return dialog;  
    103.         }  
    104.     }  
    105.       
    106. }  

    可以看到,通过Builder来设置AlertDialog中的title, message, button等参数, 这些参数都存储在类型为AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了与之对应的成员变量。在调用Builder类的create函数时才创建AlertDialog, 并且将Builder成员变量P中保存的参数应用到AlertDialog的mAlert对象中,即P.apply(dialog.mAlert)代码段。我们看看apply函数的实现 : 

     

     

    [java] view plain copy
     
    1. public void apply(AlertController dialog) {  
    2.     if (mCustomTitleView != null) {  
    3.         dialog.setCustomTitle(mCustomTitleView);  
    4.     } else {  
    5.         if (mTitle != null) {  
    6.             dialog.setTitle(mTitle);  
    7.         }  
    8.         if (mIcon != null) {  
    9.             dialog.setIcon(mIcon);  
    10.         }  
    11.         if (mIconId >= 0) {  
    12.             dialog.setIcon(mIconId);  
    13.         }  
    14.         if (mIconAttrId > 0) {  
    15.             dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));  
    16.         }  
    17.     }  
    18.     if (mMessage != null) {  
    19.         dialog.setMessage(mMessage);  
    20.     }  
    21.     if (mPositiveButtonText != null) {  
    22.         dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,  
    23.                 mPositiveButtonListener, null);  
    24.     }  
    25.     if (mNegativeButtonText != null) {  
    26.         dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,  
    27.                 mNegativeButtonListener, null);  
    28.     }  
    29.     if (mNeutralButtonText != null) {  
    30.         dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,  
    31.                 mNeutralButtonListener, null);  
    32.     }  
    33.     if (mForceInverseBackground) {  
    34.         dialog.setInverseBackgroundForced(true);  
    35.     }  
    36.     // For a list, the client can either supply an array of items or an  
    37.     // adapter or a cursor  
    38.     if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {  
    39.         createListView(dialog);  
    40.     }  
    41.     if (mView != null) {  
    42.         if (mViewSpacingSpecified) {  
    43.             dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,  
    44.                     mViewSpacingBottom);  
    45.         } else {  
    46.             dialog.setView(mView);  
    47.         }  
    48.     }  
    49. }  

    实际上就是把P中的参数挨个的设置到AlertController中, 也就是AlertDialog中的mAlert对象。从AlertDialog的各个setter方法中我们也可以看到,实际上也都是调用了mAlert对应的setter方法。在这里,Builder同时扮演了上文中提到的builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。

     


    优点与缺点

    优点 :
    1、良好的封装性, 使用建造者模式可以使客户端不必知道产品内部组成的细节;
    2、建造者独立,容易扩展;
    3、在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。

    缺点 :
    1、会产生多余的Builder对象以及Director对象,消耗内存;
    2、对象的构建过程暴露。

  • 相关阅读:
    Picasso
    ImageLoader
    OkHttp3源码详解(二) 整体流程
    Android事件总线(三)otto用法全解析
    硅谷新闻9--图片三级缓存
    OkHttp3源码详解(一) Request类
    网络编程总结
    名称空间(Namespaces)(转)
    文件的增删改查
    生成器表达式和面向过程编程
  • 原文地址:https://www.cnblogs.com/vegetate/p/9997198.html
Copyright © 2020-2023  润新知