本文主要是介绍Android设计模式学习之Builder模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Android设计模式学习之观察者模式
建造者模式(Builder Pattern),是创造性模式之一,Builder 模式的目的则是为了将对象的构建与展示分离。Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。
模式的使用场景
1.相同的方法,不同的执行顺序,产生不同的事件结果时;
2.多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时;
3.产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
UML类图
角色介绍
Product 产品类 : 产品的抽象类;
Builder : 抽象类, 规范产品的组建,一般是由子类实现具体的组件过程;
ConcreteBuilder : 具体的构建器;
Director : 统一组装过程(可省略)。
Builder模式简单实现
Builder模式最典型的例子,就是组装电脑的例子了
创建产品类
public class Computer {private String mCpu;private String mRam;public void setmCpu(String mCpu) {this.mCpu = mCpu;}public void setmRam(String mRam) {this.mRam = mRam;}
}
创建Builder类
组装电脑有一套组装方法的模版,就是一个抽象的Builder类,里面提供了安装CPU、内存的方法,以及组装成电脑的create方法:
public abstract class Builder {public abstract void buildCpu(String cpu);public abstract void buildRam(String ram);public abstract Computer create();
}
实现了抽象的Builder类,ComputerBuilder类用于组装电脑:
public class ComputerBuilder extends Builder {private Computer mComputer = new Computer();@Overridepublic void buildCpu(String cpu) {mComputer.setmCpu(cpu);}@Overridepublic void buildRam(String ram) {mComputer.setmRam(ram);}@Overridepublic Computer create() {return mComputer;}
}
用Dirextor指挥者类来统一组装过程
public class Direcror {Builder mBuild=null;public Direcror(Builder build){this.mBuild=build;}public Computer CreateComputer(String cpu,String mainboard,String ram){//规范建造流程this.mBuild.buildMainboard(mainboard); this.mBuild.buildRam(ram);return mBuild.create();}
}
客户端调用指挥者类
最后商家用指挥者类组装电脑。我们只需要提供我们想要的CPU,内存就可以了,至于商家怎样组装的电脑我们无需知道。
public class CreatComputer {public static void main(String[]args){Builder mBuilder=new MoonComputerBuilder();Direcror mDirecror=new Direcror(mBuilder);//组装电脑mDirecror.CreateComputer("i5-3210","DDR4");}
}
Android源码中的Builder模式
在Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象。简单示例如下 :
//显示基本的AlertDialog private void showDialog(Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(R.drawable.icon); builder.setTitle("头部"); builder.setMessage("内容"); builder.setPositiveButton("Button1", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { setTitle("点击了对话框上的Button1"); } }).setNeutralButton("Button2", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { setTitle("点击了对话框上的Button2"); } }); builder.create().show(); // 构建AlertDialog, 并且显示}
下面我们看看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 : 构造AlertDialogAlertDialog(Context context, int theme, boolean createContextWrapper) {super(context, resolveDialogTheme(context, theme), createContextWrapper);mWindow.alwaysReadCloseOnTouchAttr();mAlert = new AlertController(getContext(), this, getWindow());}// 实际上调用的是mAlert的setTitle方法@Overridepublic 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 cursorif ((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,代码可以参考系统的AlertDialog
public 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);}
}
代码调用
@Overridepublic 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 模式创建对象的客户,需要具备更多的领域知识。
这篇关于Android设计模式学习之Builder模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!