模式的定义

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

使用场景

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

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

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

UML类图

角色介绍

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

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

ConcreteBuilder : 具体的构建器.

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

简单示例

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

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

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

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

[java] view plaincopy
  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、对象的构建过程暴露。

转载于:https://www.cnblogs.com/vegetate/p/9997198.html

Android源码分析之Builder模式相关推荐

  1. 【OkHttp】OkHttp 源码分析 ( OkHttpClient.Builder 构造器源码分析 )

    OkHttp 系列文章目录 [OkHttp]OkHttp 简介 ( OkHttp 框架特性 | Http 版本简介 ) [OkHttp]Android 项目导入 OkHttp ( 配置依赖 | 配置 ...

  2. Android源码分析-PackageManagerService(PMS)源码分析(三)- queryIntentActivities函数来查找activity

    queryIntentActivities函数的作用: 在Android应用程序开发中,用startActivity可以开启另外一个Activity或应用.startActivity函数必须包含Int ...

  3. Android源码分析 - Framework层的Binder(客户端篇)

    开篇 本篇以aosp分支android-11.0.0_r25作为基础解析 我们在之前的文章中,从驱动层面分析了Binder是怎样工作的,但Binder驱动只涉及传输部分,待传输对象是怎么产生的呢,这就 ...

  4. Android源码分析 - Zygote进程

    开篇 本篇以android-11.0.0_r25作为基础解析 上一篇文章Android源码分析 - init进程,我们分析了Android第一个用户进程init进程的启动过程和之后的守护服务 init ...

  5. Android源码分析-全面理解Context

    前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...

  6. Android源码分析--MediaServer源码分析(二)

    在上一篇博客中Android源码分析–MediaServer源码分析(一),我们知道了ProcessState和defaultServiceManager,在分析源码的过程中,我们被Android的B ...

  7. Android源码分析(十一)-----Android源码中如何引用aar文件

    一:aar文件如何引用 系统Settings中引用bidehelper-1.1.12.aar 文件为例 源码地址:packages/apps/Settings/Android.mk LOCAL_PAT ...

  8. Android源码分析(三)-----系统框架设计思想

    一 : 术在内而道在外 Android系统的精髓在源码之外,而不在源码之内,代码只是一种实现人类思想的工具,仅此而已...... 近来发现很多关于Android文章都是以源码的方向入手分析Androi ...

  9. Android源码分析工具及方法

    转载自:http://bbs.pediy.com/showthread.php?t=183278 标 题: [原创]Android源码分析工具及方法 作 者: MindMac 时 间: 2014-01 ...

  10. Android 源码分析工具

    2019独角兽企业重金招聘Python工程师标准>>> 标 题: [原创]Android源码分析工具及方法 作 者: MindMac 时 间: 2014-01-02,09:32:35 ...

最新文章

  1. 如何获取js对象的对象名
  2. JAVA 之异常处理与IO流
  3. nginx配置多个server
  4. 对CAS机制的理解(一)
  5. python多线程下载文件
  6. Redis:05---键的基本命令(下) 生存周期
  7. 爸爸的素质决定孩子飞多高,爸爸们请反复看!!!
  8. 卡尔曼滤波、扩展卡尔曼滤波、无迹卡尔曼滤波以及粒子滤波原理
  9. java io .log_namenode无法启动:java.io.FileNotFoundException: .log (Permission denied)
  10. 【开源物联网】CoAP协议解析和RESTful开源实现
  11. android脚本,安卓好用的脚本程序—Gscript
  12. fastdfs断点续传
  13. 高精度加法 problem A+B
  14. 摩羯座 计算机专业,为什么说摩羯座是一个很“作”的星座?
  15. HOOF(Histogram of Oriented Optical Flow)特征
  16. S4 BP供应商批导
  17. Camtasia2023最好用的电脑屏幕录制软件
  18. 远程访问家中路由器,实现web、ssh、aria2、ftp功能
  19. Asp.Net无刷新上传并裁剪头像
  20. 揭秘:中国第一代黑客攻防实录

热门文章

  1. picpick尺子像素大小精度不够准确_袖珍大小MFJ-223 1-60MHz彩色图形VNA矢量网络分析仪...
  2. 以太坊 solidity 函数修饰符总结 public、private、internal、external、view、pure的区别
  3. 比特币 POW 白皮书 区块篡改成功的概率 代码 注释详解
  4. 基于SSM的NBA篮球球队运营系统
  5. 远程计算机统考试题,2015年电大远程网络教育计算机应用基础统考模拟试题集...
  6. php之mvc设计模式的原理和实现
  7. Commons Collections4 简单使用
  8. acWing 1296 聪明的燕姿
  9. 2.4.PHP7.1 狐教程-【PHP常量】
  10. LayaAir 图集动画1—图集制作