Android 设计模式学习之 Builder 模式
2017-11-24 00:00
369 查看
新媒体管家
点击上方“程序员大咖”,选择“置顶公众号”
关键时刻,第一时间送达!
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_jpg/ow6przZuPIG18kzbzliaybJA5y49s2zn9OVOziayVbGUmujwPYZLVGmbMalFKZr8GstdMVntUWN6NVaibmrbsQR4w/640?wxfrom=5&wx_lazy=1)
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_gif/XUfq62QbuNheicTsP0zLsEku39Qq31PtMUcibd8b0Po5Tna1yeC4WYIyVtv6mkUHw54wSVsQCVeicwyZL163X2PmA/0.gif?wxfrom=5&wx_lazy=1)
Android 设计模式学习之观察者模式
建造者模式(Builder Pattern),是创造性模式之一,Builder 模式的目的则是为了将对象的构建与展示分离。Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。
相同的方法,不同的执行顺序,产生不同的事件结果时;
多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时;
产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_jpg/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyaMvJic9Sb0JWcjr1icNOyAopbm6hm0sqdqAcic3gUpWlXUO8lYdoG8Ac7A/640.jpeg?wxfrom=5&wx_lazy=1)
角色介绍
Product 产品类 : 产品的抽象类;
Builder : 抽象类, 规范产品的组建,一般是由子类实现具体的组件过程;
ConcreteBuilder : 具体的构建器;
Director : 统一组装过程(可省略)。
Builder模式最典型的例子,就是组装电脑的例子了 。
创建产品类
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyavybTRXfhjuN0JyKZSXVyWCate9btOdrdQY3iaLFDL3uQ9UTXv83WZrQ/0.png)
创建Builder类
组装电脑有一套组装方法的模版,就是一个抽象的Builder类,里面提供了安装CPU、内存的方法,以及组装成电脑的create方法:
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGya0Kx9A2GROcPmR4lIWS3gaYxVeXTkCNENYv9C58yln7Qibl5wmXbSSHQ/0.png)
实现了抽象的Builder类,ComputerBuilder类用于组装电脑:
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyahG3bGANEFmAbPz64k1dm0wlC9XHhFBVVCNSNgpibANYYWFQV9uDBQIw/0.png)
用Dirextor指挥者类来统一组装过程
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyad3Ig5sjkz1Y7hOsPyWyUHzukyupkNZlGnwn9CEsBgpz18AnPTu0FeA/0.png)
客户端调用指挥者类
最后商家用指挥者类组装电脑。我们只需要提供我们想要的CPU,内存就可以了,至于商家怎样组装的电脑我们无需知道。
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyaicrmYbL6NsAhDNFyMic6Xkzbb6p6cw2YWHr2icXAUKzGaiaohsGU2m4icow/0.png)
在Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象。简单示例如下 :
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyapuqYxjbibzk8nBuf4sz4MNncvyTlyLKrPyJ6auXwb8ias3HT5YJHdllA/0.png)
下面我们看看AlertDialog的相关源码
可以看到,通过Builder来设置AlertDialog中的title, message, button等参数, 这些参数都存储在类型为AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了与之对应的成员变量。在调用Builder类的create函数时才创建AlertDialog, 并且将Builder成员变量P中保存的参数应用到AlertDialog的mAlert对象中,即P.apply(dialog.mAlert)代码段。我们看看apply函数的实现
:
实际上就是把P中的参数挨个的设置到AlertController中, 也就是AlertDialog中的mAlert对象。从AlertDialog的各个setter方法中我们也可以看到,实际上也都是调用了mAlert对应的setter方法。在这里,Builder同时扮演了上文中提到的builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。
我们可以采用系统已经提供好的Builder设计模式构建整个应用的万能Dialog,代码可以参考系统的AlertDialog
代码调用
最后总结一下Buider模式的优缺点:
Builder 模式的优点:
1.将一个复杂对象的创建过程封装起来,使得客户端不必知道产品内部组成的细节;
2.允许对象通过多个步骤来创建,并且可以改变过程和选择需要的过程;
3.产品的实现可以被替换,因为客户端只看到一个抽象的接口;
创建者独立,容易扩展。
Builder 模式缺点:
1.会产生多余的 Builder 对象以及 Director 对象,消耗内存;
2.与工厂模式相比,采用 Builder 模式创建对象的客户,需要具备更多的领域知识。
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz/xdukSbkNKELjkx820E1o9piblKCpicic3SnoEgzVlITYJ4sFnQ87s1SN1B99msknUp2Leg7LOr6MhXYx7GZWaMhaQ/640.jpeg)
![](https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_gif/XUfq62QbuNgHYMf7ibbYmAp706MwbaDWic4lRqcIExI5icnL29JpcJNNP2GoBsDSCAhz4hG9IpCdOfjodE40C1Ldw/0.gif)
[b]
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_gif/G1TofAf0fqgmKZQJjj39ceYg5aeBfPwxUaibqpUJfFp7R3GYWibpmFTrabicaljvDbtkkcPicCWwdMibzvkjR36bA2A/0?)
【点击成为安卓大神】[/b]
点击上方“程序员大咖”,选择“置顶公众号”
关键时刻,第一时间送达!
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_gif/XUfq62QbuNheicTsP0zLsEku39Qq31PtMUcibd8b0Po5Tna1yeC4WYIyVtv6mkUHw54wSVsQCVeicwyZL163X2PmA/0.gif?wxfrom=5&wx_lazy=1)
Android 设计模式学习之观察者模式
建造者模式(Builder Pattern),是创造性模式之一,Builder 模式的目的则是为了将对象的构建与展示分离。Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。
模式的使用场景
相同的方法,不同的执行顺序,产生不同的事件结果时;多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时;
产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
UML类图
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_jpg/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyaMvJic9Sb0JWcjr1icNOyAopbm6hm0sqdqAcic3gUpWlXUO8lYdoG8Ac7A/640.jpeg?wxfrom=5&wx_lazy=1)
角色介绍
Product 产品类 : 产品的抽象类;
Builder : 抽象类, 规范产品的组建,一般是由子类实现具体的组件过程;
ConcreteBuilder : 具体的构建器;
Director : 统一组装过程(可省略)。
Builder模式简单实现
Builder模式最典型的例子,就是组装电脑的例子了 。创建产品类
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyavybTRXfhjuN0JyKZSXVyWCate9btOdrdQY3iaLFDL3uQ9UTXv83WZrQ/0.png)
创建Builder类
组装电脑有一套组装方法的模版,就是一个抽象的Builder类,里面提供了安装CPU、内存的方法,以及组装成电脑的create方法:
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGya0Kx9A2GROcPmR4lIWS3gaYxVeXTkCNENYv9C58yln7Qibl5wmXbSSHQ/0.png)
实现了抽象的Builder类,ComputerBuilder类用于组装电脑:
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyahG3bGANEFmAbPz64k1dm0wlC9XHhFBVVCNSNgpibANYYWFQV9uDBQIw/0.png)
用Dirextor指挥者类来统一组装过程
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyad3Ig5sjkz1Y7hOsPyWyUHzukyupkNZlGnwn9CEsBgpz18AnPTu0FeA/0.png)
客户端调用指挥者类
最后商家用指挥者类组装电脑。我们只需要提供我们想要的CPU,内存就可以了,至于商家怎样组装的电脑我们无需知道。
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyaicrmYbL6NsAhDNFyMic6Xkzbb6p6cw2YWHr2icXAUKzGaiaohsGU2m4icow/0.png)
Android源码中的Builder模式
在Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象。简单示例如下 :![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/eL7YiacLdzwp4Qgxw6jt7QGsiakHmIdGyapuqYxjbibzk8nBuf4sz4MNncvyTlyLKrPyJ6auXwb8ias3HT5YJHdllA/0.png)
下面我们看看AlertDialog的相关源码
// AlertDialog public class AlertDialog extends Dialog implements DialogInterface { // Controller, 接受Builder成员变量P中的各个参数 private AlertController mAlert; // 构造函数 protected AlertDialog(Context context, int theme) { this(context, theme, true); } // 4 : 构造AlertDialog AlertDialog(Context context, int theme, boolean createContextWrapper) { super(context, resolveDialogTheme(context, theme), createContextWrapper); mWindow.alwaysReadCloseOnTouchAttr(); mAlert = new AlertController(getContext(), this, getWindow()); } // 实际上调用的是mAlert的setTitle方法 @Override public void setTitle(CharSequence title) { super.setTitle(title); mAlert.setTitle(title); } // 实际上调用的是mAlert的setCustomTitle方法 public void setCustomTitle(View customTitleView) { mAlert.setCustomTitle(customTitleView); } public void setMessage(CharSequence message) { mAlert.setMessage(message); } // AlertDialog其他的代码省略 // ************ Builder为AlertDialog的内部类 ******************* public static class Builder { // 1 : 存储AlertDialog的各个参数, 例如title, message, icon等. private final AlertController.AlertParams P; // 属性省略 /** * Constructor using a context for this builder and the {@link AlertDialog} it creates. */ public Builder(Context context) { this(context, resolveDialogTheme(context, 0)); } public Builder(Context context, int theme) { P = new AlertController.AlertParams(new ContextThemeWrapper( context, resolveDialogTheme(context, theme))); mTheme = theme; } // Builder的其他代码省略 ...... // 2 : 设置各种参数 public Builder setTitle(CharSequence title) { P.mTitle = title; return this; } public Builder setMessage(CharSequence message) { P.mMessage = message; return this; } public Builder setIcon(int iconId) { P.mIconId = iconId; return this; } public Builder setPositiveButton(CharSequence text, final OnClickListener listener) { P.mPositiveButtonText = text; P.mPositiveButtonListener = listener; return this; } public Builder setView(View view) { P.mView = view; P.mViewSpacingSpecified = false; return this; } // 3 : 构建AlertDialog, 传递参数 public AlertDialog create() { // 调用new AlertDialog构造对象, 并且将参数传递个体AlertDialog final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false); // 5 : 将P中的参数应用的dialog中的mAlert对象中 P.apply(dialog.mAlert); dialog.setCancelable(P.mCancelable); if (P.mCancelable) { dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(P.mOnCancelListener); if (P.mOnKeyListener != null) { dialog.setOnKeyListener(P.mOnKeyListener); } return dialog; } }}
可以看到,通过Builder来设置AlertDialog中的title, message, button等参数, 这些参数都存储在类型为AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了与之对应的成员变量。在调用Builder类的create函数时才创建AlertDialog, 并且将Builder成员变量P中保存的参数应用到AlertDialog的mAlert对象中,即P.apply(dialog.mAlert)代码段。我们看看apply函数的实现
:
public void apply(AlertController dialog) { if (mCustomTitleView != null) { dialog.setCustomTitle(mCustomTitleView); } else { if (mTitle != null) { dialog.setTitle(mTitle); } if (mIcon != null) { dialog.setIcon(mIcon); } if (mIconId >= 0) { dialog.setIcon(mIconId); } if (mIconAttrId > 0) { dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId)); } } if (mMessage != null) { dialog.setMessage(mMessage); } if (mPositiveButtonText != null) { dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText, mPositiveButtonListener, null); } if (mNegativeButtonText != null) { dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText, mNegativeButtonListener, null); } if (mNeutralButtonText != null) { dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText, mNeutralButtonListener, null); } if (mForceInverseBackground) { dialog.setInverseBackgroundForced(true); } // For a list, the client can either supply an array of items or an // adapter or a cursor if ((mItems != null) || (mCursor != null) || (mAdapter != null)) { createListView(dialog); } if (mView != null) { if (mViewSpacingSpecified) { dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom); } else { dialog.setView(mView); } } }
实际上就是把P中的参数挨个的设置到AlertController中, 也就是AlertDialog中的mAlert对象。从AlertDialog的各个setter方法中我们也可以看到,实际上也都是调用了mAlert对应的setter方法。在这里,Builder同时扮演了上文中提到的builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。
在实际项目中的应用
我们可以采用系统已经提供好的Builder设计模式构建整个应用的万能Dialog,代码可以参考系统的AlertDialogpublic static class Builder { private AlertController.AlertParams P; public Builder(Context context) { this(context, 0); } public Builder(Context context, int themeResId) { P = new AlertController.AlertParams(); P.themeResId = themeResId; P.context = context; } public Builder setText(int viewId, CharSequence text) { P.textArray.put(viewId, text); return this; } public Builder setOnClickListener(int viewId, View.OnClickListener listener) { P.clickArray.put(viewId, listener); return this; } public Builder setContentView(int layoutId) { P.view = null; P.layoutId = layoutId; return this; } public Builder setContentView(View view) { P.layoutId = 0; P.view = view; return this; } /** * Sets whether the dialog is cancelable or not. Default is true. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setCancelable(boolean cancelable) { P.cancelable = cancelable; return this; } /** * Sets the callback that will be called if the dialog is canceled. * <p> * <p>Even in a cancelable dialog, the dialog may be dismissed for reasons other than * being canceled or one of the supplied choices being selected. * If you are interested in listening for all cases where the dialog is dismissed * and not just when it is canceled, see * {@link #setOnDismissListener(OnDismissListener) setOnDismissListener}.</p> * * @return This Builder object to allow for chaining of calls to set methods * @see #setCancelable(boolean) * @see #setOnDismissListener(OnDismissListener) */ public Builder setOnCancelListener(OnCancelListener onCancelListener) { P.onCancelListener = onCancelListener; return this; } /** * Sets the callback that will be called when the dialog is dismissed for any reason. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnDismissListener(OnDismissListener onDismissListener) { P.onDismissListener = onDismissListener; return this; } /** * Sets the callback that will be called if a key is dispatched to the dialog. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnKeyListener(OnKeyListener onKeyListener) { P.onKeyListener = onKeyListener; return this; } /** * Creates an {@link AlertDialog} with the arguments supplied to this * builder. * <p/> * Calling this method does not display the dialog. If no additional * processing is needed, {@link #show()} may be called instead to both * create and display the dialog. */ public BaseDialog create() { // Context has already been wrapped with the appropriate theme. final BaseDialog dialog = new BaseDialog(P.context, P.themeResId); P.apply(dialog.mAlert); dialog.setCancelable(P.cancelable); if (P.cancelable) { dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(P.onCancelListener); dialog.setOnDismissListener(P.onDismissListener); if (P.onKeyListener != null) { dialog.setOnKeyListener(P.onKeyListener); } return dialog; } /** * Creates an {@link AlertDialog} with the arguments supplied to this * builder and immediately displays the dialog. * <p/> * Calling this method is functionally identical to: * <pre> * AlertDialog dialog = builder.create(); * dialog.show(); * </pre> */ public BaseDialog show() { final BaseDialog dialog = create(); dialog.show(); return dialog; } }
class AlertController { private DialogViewHelper mViewHelper; private BaseDialog mDialog; private Window mWindow; public AlertController(BaseDialog dialog, Window window) { mDialog = dialog; mWindow = window; } /** * 获取Dialog * @return */ public BaseDialog getDialog() { return mDialog; } /** * 获取window * @return */ public Window getWindow() { return mWindow; } public DialogViewHelper getViewHelper() { return mViewHelper; } /** * 设置View的辅助 * @param viewHelper */ public void setDialogViewHelper(DialogViewHelper viewHelper) { this.mViewHelper = viewHelper; } /** * 设置文本 * @param viewId * @param text */ public void setText(int viewId, CharSequence text) { mViewHelper.setText(viewId, text); } /** * 设置点击事件 * @param viewId * @param listener */ public void setOnClickListener(int viewId, View.OnClickListener listener) { mViewHelper.setOnClickListener(viewId, listener); } /** * 通过id获取View * @param viewId * @param <T> * @return */ public <T extends View> T getView(int viewId) { return mViewHelper.getView(viewId); }}
代码调用
@Override public void onClick(View v) { BaseDialog dialog = new BaseDialog.Builder(this) .setContentView(R.layout.detail_dialog).fullWith() .fromBottom(false) .show(); }
最后总结一下Buider模式的优缺点:
Builder 模式的优点:
1.将一个复杂对象的创建过程封装起来,使得客户端不必知道产品内部组成的细节;
2.允许对象通过多个步骤来创建,并且可以改变过程和选择需要的过程;
3.产品的实现可以被替换,因为客户端只看到一个抽象的接口;
创建者独立,容易扩展。
Builder 模式缺点:
1.会产生多余的 Builder 对象以及 Director 对象,消耗内存;
2.与工厂模式相比,采用 Builder 模式创建对象的客户,需要具备更多的领域知识。
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz/xdukSbkNKELjkx820E1o9piblKCpicic3SnoEgzVlITYJ4sFnQ87s1SN1B99msknUp2Leg7LOr6MhXYx7GZWaMhaQ/640.jpeg)
来自:CSDN-马云龙
http://blog.csdn.net/u012124438/article/details/59777619
程序员大咖整理发布,转载请联系作者获得授权![](https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_gif/XUfq62QbuNgHYMf7ibbYmAp706MwbaDWic4lRqcIExI5icnL29JpcJNNP2GoBsDSCAhz4hG9IpCdOfjodE40C1Ldw/0.gif)
[b]
【点击成为安卓大神】[/b]
相关文章推荐
- Android设计模式学习(包含Java设计模式)-Builder模式-AJDesignMode03
- Android设计模式学习之Builder模式
- 【AndroidUniversalImageLoader】源码学习之设计模式(Builder,Singleton,Strategy)
- Android设计模式学习笔记(Builder模式)
- .Net设计模式学习笔记(四):建造者模式(Builder Pattern)
- 设计模式学习笔记八:建造者模式(Builder Pattern)
- C# 设计模式学习四 Builder生成器模式(关于映射实现补充)
- 设计模式学习笔记--Builder生成器模式
- 设计模式学习---Builder(构造器)
- Android设计模式之Builder
- 设计模式之Builder 的学习笔记
- 设计模式学习----Builder模式
- 学习设计模式(一) Builder
- HeadFirst 设计模式学习笔记17--建筑者(Builder)模式拾零
- 设计模式学习总结2 - 创建型2 - Builder生成器模式
- 设计模式学习笔记(四)——Builder生成器模式
- 设计模式学习笔记(四)——Builder生成器模式
- 面向对象设计模式学习---Builder模式(创建型)
- 设计模式学习之路——Builder 生成器模式
- 阿Sam的设计模式学习笔记---- Builder模式