Android设计模式学习之Builder模式

2024-06-24 05:32

本文主要是介绍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模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1089289

相关文章

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

2025最新版Android Studio安装及组件配置教程(SDK、JDK、Gradle)

《2025最新版AndroidStudio安装及组件配置教程(SDK、JDK、Gradle)》:本文主要介绍2025最新版AndroidStudio安装及组件配置(SDK、JDK、Gradle... 目录原生 android 简介Android Studio必备组件一、Android Studio安装二、A

C++中的解释器模式实例详解

《C++中的解释器模式实例详解》这篇文章总结了C++标准库中的算法分类,还介绍了sort和stable_sort的区别,以及remove和erase的结合使用,结合实例代码给大家介绍的非常详细,感兴趣... 目录1、非修改序列算法1.1 find 和 find_if1.2 count 和 count_if1

Redis中群集三种模式的实现

《Redis中群集三种模式的实现》Redis群集有三种模式,分别是主从同步/复制、哨兵模式、Cluster,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1. Redis三种模式概述2、Redis 主从复制2.1 主从复制的作用2.2 主从复制流程2

深入理解MySQL流模式

《深入理解MySQL流模式》MySQL的Binlog流模式是一种实时读取二进制日志的技术,允许下游系统几乎无延迟地获取数据库变更事件,适用于需要极低延迟复制的场景,感兴趣的可以了解一下... 目录核心概念一句话总结1. 背景知识:什么是 Binlog?2. 传统方式 vs. 流模式传统文件方式 (非流式)流

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程