定义

The intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.
将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示

首先说明,大部分Android使用的并不是标准的 Builder pattern ,而是使用的变种的Build模式。

这里我们只讨论这种变种的模式。

先看一下OkHttp的源码实现:

OkHttpClient(Builder builder) {this.dispatcher = builder.dispatcher;this.proxy = builder.proxy;this.protocols = builder.protocols;this.connectionSpecs = builder.connectionSpecs;this.interceptors = Util.immutableList(builder.interceptors);this.networkInterceptors = Util.immutableList(builder.networkInterceptors);this.eventListenerFactory = builder.eventListenerFactory;this.proxySelector = builder.proxySelector;this.cookieJar = builder.cookieJar;this.cache = builder.cache;this.internalCache = builder.internalCache;this.socketFactory = builder.socketFactory;

OkHttp使用Build对象为分离复杂的对象构建,并使构建过程可以创造出不同功能的对象。

对应了Build模式的定义。我参考了很多文章对Build模式的理解,大部分都从构造方法有4个参数,可以考虑使用做为出发点。我一开始也是从这里从发,写着写着发现和定义不同了。我只会去考虑去使用Build来解决参数的问题,而这个问题set方法也可解决,只是没有build看的舒服和好用而已。

写到这里可能会引起不同理解和不同的看法,这也是我的目的,从单纯的记录到思想的碰撞。所以,看到的人务必要有自己的理解,如果可以写到评论,让我也可以得到启发。或者可以直接证明我的是错误,帮助我提升,多谢。

实际场景演示

开发中我们经常使用DiaLog这个widget,但是由于不同样式的Dialog,我们要写好的,导致维护成本变大。大多数人都会对Dialog封装,我们也从这里开始。

我的理想是这个Dialog可以忽略不同布局的影响。这样所有的Dialog就可以使这一个类来创建。

先看看Dialog怎么创建并显示出来

Dialog dialog=new Dialog(this);
dialog.setContentView(R.layout.comm_dialog);
dialog.show();

从上面分析出来只需要三步就可以显示出来个dialog,而且是自定义布局的。

而可以看出必要的参数只有两个,Context 和layout。也就是说封装的Base类只需要这两个参数。

上代码

public class CommonDialog extends Dialog {public CommonDialog(@NonNull Context context) {super(context);}public CommonDialog(@NonNull Context context, int themeResId) {super(context, themeResId);}protected CommonDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) {super(context, cancelable, cancelListener);this.setContentView(R.layout.comm_dialog);}
}

Dialog不考虑在布局中使用,优化后:

public class CommonDialog extends Dialog {public CommonDialog(@NonNull Context context) {super(context);this.setContentView(R.layout.comm_dialog);}
}

希望布局是创建的时候传入自定义的:

public class CommonDialog extends Dialog {public CommonDialog(@NonNull Context context, @LayoutRes int layoutId) {super(context);this.setContentView(layoutId);}
}

此时创建这个dialog代码:

CommonDialog commonDialog = new CommonDialog(this,R.layout.comm_dialog);
commonDialog.show();

dialog宽高也希望从外部传入,改进:

public class CommonDialog extends Dialog {public CommonDialog(@NonNull Context context, @LayoutRes int layoutId, int width, int height) {super(context);this.setContentView(layoutId);WindowManager.LayoutParams attributes = getWindow().getAttributes();attributes.width = width;attributes.height = height;getWindow().setAttributes(attributes);}
}

虽然此时可以显示一个自定义布局的dialog,但是除了显示和隐藏,我们根本无法做交互。

我们希望可以拿到布局的控件进行交互,改进:

public class CommonDialog extends Dialog {private View mRoot;public CommonDialog(@NonNull Context context, @LayoutRes int layoutId, int width, int height) {super(context);mRoot = LayoutInflater.from(context).inflate(layoutId, null, false);this.setContentView(mRoot);WindowManager.LayoutParams attributes = getWindow().getAttributes();attributes.width = width;attributes.height = height;getWindow().setAttributes(attributes);}public View getView(@IdRes int id) {return mRoot.findViewById(id);}
}

还希望style可以修改,同理:

public class CommonDialog extends Dialog {private View mRoot;public CommonDialog(@NonNull Context context, @LayoutRes int layoutId, int width, int height, @StyleRes int style) {super(context, style);mRoot = LayoutInflater.from(context).inflate(layoutId, null, false);this.setContentView(mRoot);WindowManager.LayoutParams attributes = getWindow().getAttributes();attributes.width = width;attributes.height = height;getWindow().setAttributes(attributes);}public View getView(@IdRes int id) {return mRoot.findViewById(id);}
}

还有点击外部可以消失、设置动画…等功能,先不说。此时,看看我们的Dialog创建的代码。

CommonDialog commonDialog = new CommonDialog(this,R.layout.comm_dialog, ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT,R.style.AlertDialog_AppCompat);

这么长的构造,我们得优化一下了,可以使set方法优化和今天主角Build模式。

set方法部署主角也很简单,不用说,直接看使用Build的模式优化的:

public class CommonDialog extends Dialog {private Build mBuild;public CommonDialog(@NonNull Build build) {// 使用自定义Dialog样式super(build.mContext, build.mStyle);mBuild = build;build();}private void build() {setContentView(mBuild.mRoot);// 设置宽和高WindowManager.LayoutParams params = getWindow().getAttributes();params.height = this.mBuild.mHeight;params.width = this.mBuild.mWidth;getWindow().setAttributes(params);// 设置点击Dialog以外的区域时Dialog消失setCanceledOnTouchOutside(mBuild.mCancel);}public <T extends View> T getView(@IdRes int viewId) {return this.mBuild.mRoot.findViewById(viewId);}public void setButtonOnClickListener(@IdRes int viewId,@NonNull View.OnClickListener onClickListener) {Button button = this.mBuild.mRoot.findViewById(viewId);button.setOnClickListener(v -> onClickListener.onClick(button));}public static class Build {private Context mContext;private View mRoot;private int mWidth;private int mHeight;private boolean mCancel;private int mStyle;public Build setContext(@NonNull Context mContext) {this.mContext = mContext;return this;}public Build setLayout(@LayoutRes int mLayout) {mRoot = LayoutInflater.from(mContext).inflate(mLayout, null, false);return this;}public Build setWidth(int width) {mWidth = width;return this;}public Build setHeight(int height) {mHeight = height;return this;}public Build setText(@IdRes int viewId, @NonNull String text) {View view = mRoot.findViewById(viewId);if (view instanceof TextView) {TextView textView = (TextView) view;textView.setText(text);} else {throw new NullPointerException("找不到setText方法,原因这个view不是继承TextView");}return this;}public Build setImageResource(@IdRes int viewId, @DrawableRes int drawableResId) {View view = mRoot.findViewById(viewId);if (view instanceof ImageView) {ImageView imageView = (ImageView) view;imageView.setImageResource(drawableResId);} else {throw new NullPointerException("找不到setImageResource方法,原因这个view不是继承ImageView");}return this;}public Build setOnClickListener(@IdRes int viewId, View.OnClickListener onClickListener) {View view = mRoot.findViewById(viewId);view.setOnClickListener(v -> onClickListener.onClick(v));return this;}public Build startAnimation(@IdRes int viewId, Animation animation) {View view = mRoot.findViewById(viewId);view.startAnimation(animation);animation.start();return this;}public Build setCanceledOnTouchOutside(boolean cancel) {mCancel = cancel;return this;}public Build setStyle(@StyleRes int style) {mStyle = style;return this;}public CommonDialog build() {return new CommonDialog(this);}}
}

这个Dialog依然可以改进比如Context输入必传入参数,layout也可能是。你可以加入自己的方法。

我们再看怎么创建这个dialog

val dialog = CommonDialog.Build().setContext(this).setWidth(ViewGroup.LayoutParams.WRAP_CONTENT).setHeight(ViewGroup.LayoutParams.WRAP_CONTENT).setLayout(R.layout.common_dia_log).setText(R.id.tile, "自定义标题").setText(R.id.message, "自定义内容").setText(R.id.left_button, "确定").setText(R.id.right_button, "取消").setCanceledOnTouchOutside(true).build()
dialog.show()

这段是Kotlin的代码但是和Java也没太大的区别。可以看出,处理这种大量参数的对象构建Build模式非常舒服。

Android Builder模式相关推荐

  1. Android Builder模式在开发中的应用

    最近在学习图片加载框架Glide的时候,被他精简的写法震惊了.一句话,就可以搞定. Glide.with(mContext) .load(url) .centerCrop() .placeholder ...

  2. Android : Builder模式 详解及学习使用

    在此声明:以下内容由书籍 <Android高级进阶>学习而来. Builder模式是一种设计模式,最初被介绍于<设计模式:可复用面向对象软件的基础>,目前在Java及Andro ...

  3. android builder模式,模式设计(三:Builder模式) (转)

    模式设计(三:Builder模式) (转)[@more@] builder 本文中我将采用生产汽车的例子来讲解builder 模式. 考虑如下问题:我要建造一部车,我们希望将这个复杂的的构建与其表示分 ...

  4. android builder模式 插件,如何在Kotlin中实现Builder模式?

    首先,在大多数情况下,您不需要在Kotlin中使用构建器,因为我们有默认和命名参数 . 这使您可以写 class Car(val model: String? = null, val year: In ...

  5. Android设计模式之——Builder模式

    一.介绍 Builder模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构造流程.该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程 ...

  6. Android常用设计模式之Builder模式理解

    Android常用设计模式之Builder模式 1 单例模式 2 Builder模式 Builder模式的应用场景 总结 1 单例模式 单例模式之前有详细的介绍,可移步到链接: 常见的单例模式及其特点 ...

  7. Android使用Builder模式自定义Dialog

    首先说说为啥要自定义Dialog,在任何软件操作系统中,Dialog即对话框都是一种重要的交互模式与信息载体,而Android系统本身的Dialog拥有固定的样式,并且在5.0后采用Material ...

  8. Android常考问题(8)-设计模式:Builder模式(顺带学习了一下String的比较和final)

    今天的主要目的是学习设计模式中的Builder模式.由于java基础不牢固,在学习过程中要回过头去学习java内容,因此凑成了这样一篇驳杂的文章. Builder模式 首先是Builder设计模式的作 ...

  9. android开发模式,Android开发中无处不在的设计模式

    Android开发中无处不在的设计模式――单例模式 Android开发中无处不在的设计模式――Builder模式 前面介绍了单例模式和Builder模式,有兴趣的见上面两个链接,这篇文章侧重介绍1下视 ...

  10. Java设计模式——Builder模式

    前言 之前写Android程序的时候,经常会用到Dialog(对话框)这个控件.我们在使用Dialog,比如AlertDialog的时候就用到了这里要说明的Builder模式.现在我们来看一下这样的一 ...

最新文章

  1. 深入浅出K-Means算法
  2. 计算机辅助设计课程描述,计算机辅助设计课程教学的现状与方法
  3. android调用另一app的xml,Android 7.0+调用其他App打开文件
  4. Redis和Memcached:数据类型 过期策略 持久策略 虚拟内存 Value大小
  5. oracle子查询子查询,Oracle 单行子查询和多行子查询
  6. 将有序数组转为二叉搜索树
  7. C,C++,C#的点评
  8. 【oracle】关于创建表时用default指定默认值的坑
  9. MSSQL DBA权限获取WEBSHELL的过程
  10. 【JEECG_3.7.1】列表多表头的设计
  11. Starter Kit for ASP.NET 2.0 家族又添新丁!
  12. 互利网上数字金融典型场景: 网络借贷
  13. 层级实时记忆(HTM)脑皮质学习算法白皮书笔记
  14. 怎样开图纸便宜_一步一步教你如何看懂工程图纸,值得收藏!
  15. CentOS安装SVN
  16. 如何用od去手动脱壳
  17. 根据身份证号判断所属省份、生日及性别
  18. coreldraw梯形校正_CDR图文教程-CorelDREW折叠效果怎么做?
  19. als算法参数_ALS算法实现用户音乐打分预测
  20. 小葵花妈妈课堂开课了:《Runnable、Callable、Future、RunnableFuture、FutureTask 源码分析》

热门文章

  1. 网易面经(内含腾讯ieg/IOS一面面经)
  2. 数字信号处理重要学习资源
  3. 红帽子 linux 声卡驱动,RedHat Linux系统下安装ALSA驱动的方法
  4. 华泰证券 python 自动交易软件_量化交易策略自动搬砖自动交易软件费用
  5. 小游戏学习--获取已发布微信小游戏源码
  6. 电源模块-LM5117-BUCK- 电路
  7. 印象笔记导入html笔记,Evernote Importer|印象笔记导入
  8. 潮流计算机课设,(潮流计算的计算机算法课程设计范文.doc
  9. 机器学习——神经网络(四):BP神经网络
  10. 53-20210316华为海思Hi3516DV300的linux系统通过网口刷机(eMMC模式)