Android Builder模式
定义
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模式相关推荐
- Android Builder模式在开发中的应用
最近在学习图片加载框架Glide的时候,被他精简的写法震惊了.一句话,就可以搞定. Glide.with(mContext) .load(url) .centerCrop() .placeholder ...
- Android : Builder模式 详解及学习使用
在此声明:以下内容由书籍 <Android高级进阶>学习而来. Builder模式是一种设计模式,最初被介绍于<设计模式:可复用面向对象软件的基础>,目前在Java及Andro ...
- android builder模式,模式设计(三:Builder模式) (转)
模式设计(三:Builder模式) (转)[@more@] builder 本文中我将采用生产汽车的例子来讲解builder 模式. 考虑如下问题:我要建造一部车,我们希望将这个复杂的的构建与其表示分 ...
- android builder模式 插件,如何在Kotlin中实现Builder模式?
首先,在大多数情况下,您不需要在Kotlin中使用构建器,因为我们有默认和命名参数 . 这使您可以写 class Car(val model: String? = null, val year: In ...
- Android设计模式之——Builder模式
一.介绍 Builder模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构造流程.该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程 ...
- Android常用设计模式之Builder模式理解
Android常用设计模式之Builder模式 1 单例模式 2 Builder模式 Builder模式的应用场景 总结 1 单例模式 单例模式之前有详细的介绍,可移步到链接: 常见的单例模式及其特点 ...
- Android使用Builder模式自定义Dialog
首先说说为啥要自定义Dialog,在任何软件操作系统中,Dialog即对话框都是一种重要的交互模式与信息载体,而Android系统本身的Dialog拥有固定的样式,并且在5.0后采用Material ...
- Android常考问题(8)-设计模式:Builder模式(顺带学习了一下String的比较和final)
今天的主要目的是学习设计模式中的Builder模式.由于java基础不牢固,在学习过程中要回过头去学习java内容,因此凑成了这样一篇驳杂的文章. Builder模式 首先是Builder设计模式的作 ...
- android开发模式,Android开发中无处不在的设计模式
Android开发中无处不在的设计模式――单例模式 Android开发中无处不在的设计模式――Builder模式 前面介绍了单例模式和Builder模式,有兴趣的见上面两个链接,这篇文章侧重介绍1下视 ...
- Java设计模式——Builder模式
前言 之前写Android程序的时候,经常会用到Dialog(对话框)这个控件.我们在使用Dialog,比如AlertDialog的时候就用到了这里要说明的Builder模式.现在我们来看一下这样的一 ...
最新文章
- 深入浅出K-Means算法
- 计算机辅助设计课程描述,计算机辅助设计课程教学的现状与方法
- android调用另一app的xml,Android 7.0+调用其他App打开文件
- Redis和Memcached:数据类型 过期策略 持久策略 虚拟内存 Value大小
- oracle子查询子查询,Oracle 单行子查询和多行子查询
- 将有序数组转为二叉搜索树
- C,C++,C#的点评
- 【oracle】关于创建表时用default指定默认值的坑
- MSSQL DBA权限获取WEBSHELL的过程
- 【JEECG_3.7.1】列表多表头的设计
- Starter Kit for ASP.NET 2.0 家族又添新丁!
- 互利网上数字金融典型场景: 网络借贷
- 层级实时记忆(HTM)脑皮质学习算法白皮书笔记
- 怎样开图纸便宜_一步一步教你如何看懂工程图纸,值得收藏!
- CentOS安装SVN
- 如何用od去手动脱壳
- 根据身份证号判断所属省份、生日及性别
- coreldraw梯形校正_CDR图文教程-CorelDREW折叠效果怎么做?
- als算法参数_ALS算法实现用户音乐打分预测
- 小葵花妈妈课堂开课了:《Runnable、Callable、Future、RunnableFuture、FutureTask 源码分析》
热门文章
- 网易面经(内含腾讯ieg/IOS一面面经)
- 数字信号处理重要学习资源
- 红帽子 linux 声卡驱动,RedHat Linux系统下安装ALSA驱动的方法
- 华泰证券 python 自动交易软件_量化交易策略自动搬砖自动交易软件费用
- 小游戏学习--获取已发布微信小游戏源码
- 电源模块-LM5117-BUCK- 电路
- 印象笔记导入html笔记,Evernote Importer|印象笔记导入
- 潮流计算机课设,(潮流计算的计算机算法课程设计范文.doc
- 机器学习——神经网络(四):BP神经网络
- 53-20210316华为海思Hi3516DV300的linux系统通过网口刷机(eMMC模式)