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 DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I