一、前言

设计模式系列(参考资料:《Android源码设计模式解析与实战》——何红辉、关爱明)
单例模式
Builder模式
原型模式

二、介绍

我们开发中偶尔会遇到一些需要设置10个或以上大量参数的情况,通常情况有几种处理方式:多构造函数、setterBuilder模式

  • 1、多构造函数:这种方式虽然最方便,但也最繁琐,假设有一个方法需要设置6int型的参数,但多数情况下,这6个中总有你不想传的参数,这时候就需要约定一个规则:例如传0,但是传0又会有一个问题就是传入顺序问题,传入顺序不同并不会导致程序编译不通过,却会导致程序运行结果不正确。所以这并不是一种好方式
  • 2、setter
    虽然它可以解决多构造带来的传入顺序问题,但是它还是略显繁琐了。所以我们通常只会在JavaBean中使用setter
  • 3、Builder模式
  • 本文要介绍的一种方式,可以完美解决上述两种方式带来的弊端,让代码更加符合设计模式。参考GlideRetrofit的使用方式,它们都是通过链式调用一个一个参数连接起来的

三、定义

Builder的定义是:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

四、使用场景

主要强调两点:调用顺序多参数

  • 1、相同的方法,不同的执行顺序,需要产生不同的事件结果时
  • 2、多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同的时候
  • 3、产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用时
  • 4、当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时

五、UML图

背景:我要建造一个xsic
在这个背景下,Productxsic的抽象,也就是人,ConcreteBuilder是一个具体Builder类,继承了抽象BuilderBuilder,而Director可以是一个高层客户端模块,也可以是一个为高层客户端模块提供构建功能的中间模块

六、举例

1、抽象产品类,在UML中没有具体体现

 public abstract class Person {protected String mHead;protected int mBody;protected String mArm;protected String mLeg;protected String mHair;public abstract void setHead(String head);public abstract void setBody(int body);public void setmArm(String mArm) {this.mArm = mArm;}public void setmLeg(String mLeg) {this.mLeg = mLeg;}public void setmHair(String mHair) {this.mHair = mHair * mBody;}}

2、具体产品类,对应UML中的Product

 public class Xsic extends Person {public Xsic() {}@Overridepublic void setHead(String head) {mHead = "默认头";}@Overridepublic void setBody(int body) {mBody = 1;}}

3、抽象Builder类,对应UML中的Builder

 public abstract class Builder {public abstract Builder buildHead(String head);public abstract Builder buildBody(int body);public abstract Builder buildArm(String arm);public abstract Builder buildLeg(String leg);public abstract Builder buildHair(String hair);public abstract Person build();}

4、具体Builder类,对应UML中的ConcreteBuilder

 public class XsicBuilder extends Builder {private Xsic xsic = new Xsic();@Overridepublic Builder buildHead(String head) {xsic.setHead(head);return this;}@Overridepublic Builder buildBody(int body) {xsic.setBody(body);return this;}@Overridepublic Builder buildArm(String arm) {xsic.setmArm(arm);return this;}@Overridepublic Builder buildLeg(String leg) {xsic.setmLeg(leg);return this;}@Overridepublic Builder buildHair(String hair) {xsic.setmHair(hair);return this;}@Overridepublic Person build() {return xsic;}}

5、Director类,可以理解为为高层客户端模块提供构造方式的类,对应UML中的Director,但是通常都不会写这个类,而是直接给高层客户端模块调用。

 public class Director {private Builder mBuilder = null;public Director(Builder mBuilder) {this.mBuilder = mBuilder;}public void construct(String head, int body, String arm, String leg, String hair){mBuilder.buildHead(head).buildBody(body).buildArm(arm).buildLeg(leg).buildHair(hair).build();}}

6、客户端,在UML中没有具体体现

 public class Client {private void main(){Builder mBuilder = new XsicBuilder();Person xsic = mBuilder.buildArm("手").buildLeg("脚").buildBody("身体").buildHead("头").build();}}

这个例子里面除了明显的多参数外,还加入了调用顺序产生不同结果:buildBody调用的先后顺序会影响buildHair的结果

七、实际使用

实际使用的时候通常情况下并不会有这么多类(除非真的有抽象Builder的必要,例如要build一系列类似的事物),通常都会将Director去掉,毕竟Director的写法跟setter没什么差别。因此通常都会只写一个外部类,将Builder作为这个外部类的静态内部类。
因为使用Glide经常需要写RequestBuilder,我们这里以二次封装一个Glide工具类为例子:

public enum ImagLoader2 {INSTANCE;private static Builder mBuilder = null;public Builder getBuilder(ImageView view){mBuilder = newBuilder(view,view.getContext());return mBuilder;}private Builder newBuilder(ImageView view, Context context){return new Builder(view,context);}public static final class Builder{/* 参数 *///字符串型数据源private String mUrl = "";//资源型数据源private @DrawableRes int mRes = -1;//drawable型数据源private Drawable mDrawable = null;//目标viewprivate ImageView mView;//默认图,只取第一次设置private @DrawableRes int mIntPlaceHolder = -1;private Drawable mDrawablePlaceHolder = null;//错误图,只取第一次设置private @DrawableRes int mIntError = -1;private Drawable mDrawableError = null;//默认图private @DrawableRes int mDefault = -1;//圆角,按left、top、right、bottom顺序,只取第一次设置private int mLTRadius = 0;private int mRTRadius = 0;private int mRBRadius = 0;private int mLBRadius = 0;//全圆角,只取第一次设置private int mRadius = 0;//预览private float mThumnail = 0f;//模糊半径private int mBlurRadius = -1;//是否gif图private boolean mIsGif = false;//是否Bitmapprivate boolean mIsBmp = false;/* 参数 *///是否已经设置数据源,只取第一次设置的值private boolean mIsSourceSet = false;private boolean mIsPlaceHolderSet = false;private boolean mIsErrorSet = false;private RequestOptions mErrorRQ, mPlaceHolderRQ, mRoundCornerRQ, mPartCornerRQ;private RequestManager mGlide;private RequestBuilder mGlideBuilder;private PartCornerTransform2 mPartCornerTransform;private RoundedCorners mRoundedCorners;//四个角的圆角值public enum DIRETION{LEFT_TOP,RIGHT_TOP,RIGHT_BOTTOM,LEFT_BOTTOM}public Builder(ImageView view, Context context) {if (view == null){throw new IllegalArgumentException("目标view必须有效!");}mView = view;mGlide = Glide.with(context);}public Builder setUrl(String url){if (mIsSourceSet) return this;mUrl = url;mIsSourceSet = true;return this;}public Builder setRes(@DrawableRes int res){if (mIsSourceSet) return this;mRes = res;mIsSourceSet = true;return this;}public Builder setDrawable(Drawable drawable){if (mIsSourceSet) return this;mDrawable = drawable;mIsSourceSet = true;return this;}public Builder setDefault(@DrawableRes int res){mDefault = res;return this;}public Builder setPlaceHolder(@DrawableRes int placeHolder){if (mIsPlaceHolderSet) return this;mIntPlaceHolder = placeHolder;mIsPlaceHolderSet = true;return this;}public Builder setPlaceHolder(Drawable placeHolder){if (mIsPlaceHolderSet) return this;mDrawable = placeHolder;mIsPlaceHolderSet = true;return this;}public Builder setError(@DrawableRes int error){if (mIsErrorSet) return this;mIntError = error;mIsErrorSet = true;return this;}public Builder setError(Drawable error){if (mIsErrorSet) return this;mDrawableError = error;mIsErrorSet = true;return this;}public Builder setRadius(int radius){if (radius <= 0){throw new IllegalArgumentException("圆角值必须大于0!圆角值为:"+radius);}mRadius = radius;return this;}/*** 设置各自角的圆角值* @param radius 圆角值* @param diretion 四个角* @return Builder*/public Builder setPartRadius(int radius, DIRETION diretion){if (radius <= 0){throw new IllegalArgumentException("圆角值必须大于0!圆角值为:"+radius);}switch (diretion){case LEFT_TOP:mLTRadius = radius;break;case RIGHT_TOP:mRTRadius = radius;break;case RIGHT_BOTTOM:mRBRadius = radius;break;case LEFT_BOTTOM:mLBRadius = radius;break;}return this;}public Builder setBlurRadius(int blurRadius){if (blurRadius <= 0) {throw new IllegalArgumentException("模糊值必须大于0!模糊值为:"+blurRadius);}mBlurRadius = blurRadius;return this;}public Builder setThumnail(float thumnail){if (thumnail <= 0f){throw new IllegalArgumentException("预览图之于原图的比例不能小于0!当前为:"+thumnail);}mThumnail = thumnail;return this;}public Builder asGif(){mIsGif = true;return this;}public Builder asBitmap(){mIsBmp = true;return this;}public void build(){mGlideBuilder = null;mErrorRQ = new RequestOptions();mPlaceHolderRQ = new RequestOptions();mRoundCornerRQ = new RequestOptions();mPartCornerRQ = new RequestOptions();//数据源if (!mUrl.equals("")){mGlideBuilder = mGlide.load(mUrl);}else if (mRes != -1){mGlideBuilder = mGlide.load(mRes);}else if (mDrawable != null){mGlideBuilder = mGlide.load(mDrawable);}else {if (mDefault != -1){mGlideBuilder = mGlide.load(mDefault);}else {mGlideBuilder = mGlide.load("");}}//错误图if (mIntError != -1){mErrorRQ = mErrorRQ.error(mIntError);mGlideBuilder = mGlideBuilder.apply(mErrorRQ);}else if (mDrawableError != null){mErrorRQ = mErrorRQ.error(mDrawableError);mGlideBuilder = mGlideBuilder.apply(mErrorRQ);}//默认图if (mIntPlaceHolder != -1){mPlaceHolderRQ = mPlaceHolderRQ.placeholder(mIntPlaceHolder);mGlideBuilder = mGlideBuilder.apply(mPlaceHolderRQ);}else if (mDrawablePlaceHolder != null){mPlaceHolderRQ = mPlaceHolderRQ.placeholder(mDrawablePlaceHolder);mGlideBuilder = mGlideBuilder.apply(mPlaceHolderRQ);}//圆角if (mRadius != 0){mRoundedCorners = new RoundedCorners(mRadius);mRoundCornerRQ = RequestOptions.bitmapTransform(mRoundedCorners);mGlideBuilder = mGlideBuilder.apply(mRoundCornerRQ);}//各自圆角if (mLTRadius != 0 || mRTRadius != 0 || mRBRadius != 0 || mLBRadius != 0){mPartCornerTransform = new PartCornerTransform2(mLTRadius,mRTRadius,mRBRadius,mLBRadius);mPartCornerRQ = RequestOptions.bitmapTransform(mPartCornerTransform);mGlideBuilder = mGlideBuilder.apply(mPartCornerRQ);}//预览if (mThumnail > 0f){mGlideBuilder = mGlideBuilder.thumbnail(mThumnail);}//是否gifif (mIsGif){mGlideBuilder = mGlide.asGif();}//是否bmpif (mIsBmp){mGlideBuilder = mGlide.asBitmap();}mGlideBuilder.into(mView);}}
}

八、总结

Builder模式如果真的要吹毛求疵找出缺点的话,那就是会比普通setter或者多构造函数方式多了一个Builder对象的创建,这对于对性能要求苛刻的应用来说可能不是一个最好的选择,但是对于大多数应用来说,Builder的优势还是显而易见的。
ps:这篇和《Effective Java》第二章 第2条:遇到多个构造器参数时要考虑使用Builder内容一样,因此我就直接copy,为什么不直接跳过?因为缺了一篇的话会像少了一块拼图一样让我很难受…

【设计模式】Builder模式相关推荐

  1. 设计模式-Builder模式

    目录 一个例子(做汤) 人工做汤 机器做汤(使用Builder模式) 优缺点 优点 缺点 Builder模式属于创建型模式. 它是将一个复杂对象的构建过程隐藏起来,让使用者只关系自己要生成什么样的对象 ...

  2. 设计模式--builder 模式

    设计模式–builder 模式 说明 @author JellyfishMIX - github / blog.jellyfishmix.com LICENSE GPL-2.0 本文默认已经知道了 b ...

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

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

  4. 设计模式 —— Builder 模式

    文章目录 1 Builder 模式的核心思想 2 第一种 Builder 模式 3 第一种模式的困惑 4 第二种 Builder 模式 5 第二种 Builder 模式见解 6 参考 1 Builde ...

  5. Java 常用设计模式 -- Builder模式

    Builder模式是在Java中最流行的模式之一.它很简单,有助于保持对象不可变,并且可以使用Project Lombok的@Builder或Immutables等工具生成,仅举几例. 模式的流畅变体 ...

  6. java的设计模式 - Builder模式

    Builder 模式的目的? 构造对象的方式过于复杂,不如将之抽离出来.比如,构造器参数过多 这样说也有点抽象,举个例子吧. 举个例子 比如 非常热门的消息队列RabbitMQ 的 AMQP.Basi ...

  7. GOF 设计模式 builder模式笔记

    Builder(生成器) 意图:将一个复杂对象的构建与它的表示相分离,使得同样的构建过程可以创建不同的表示. 在以下情况使用Builder模式 当创建复杂的对象应该独立于该对象的组成部分以及它们的装配 ...

  8. Java设计模式-Builder模式

    Builder模式是将一个复杂对象的创建和表示分离,使同样的创建过程可以创建不同的表示.它属于建造类模式. 一般来说,如果一个对象的创建比较复杂,超出了构造方法所能包含的范围,就可以使用工厂模式和Bu ...

  9. 设计模式 builder模式

    也是属于对象创建类模式.使用的一般情况是,需要完成一个复杂的对象创建工作,工作通常由各个部分的子对象用一定的算法构成,比如step1,step2,step3,步骤内部常常发生剧烈的变化,但是组合在一起 ...

  10. 设计模式-Builder模式(构建者模式)

    目录 构建者模式是什么? 为什么要用构建者模式? 构建者模式是什么? 简单来说,就是用于组装具有复杂结构的实例的模式. 什么意思呢?先来看个例子,比如现在有一个类TextBuilder用来创建一个文本 ...

最新文章

  1. 必读!53个Python经典面试题详解
  2. HDU2032(杨辉三角)
  3. 如何提升科研能力?以下这点最重要!
  4. 非洲儿童(南阳oj1036)(馋)
  5. CocoaPosd使用详解
  6. css清除浮动的原理
  7. 三十岁以前不必在乎的29件事
  8. java 调用python_Java平台如何调用Python平台?
  9. 基于Java+SpringMvc+vue+element实现高效学生社团平台管理
  10. TensorFlow-RNN循环神经网络 Example 2:文本情感分析
  11. 40元老年机摇身一变成“华为”手机:半年卖了7000多台?
  12. java类加载机制ClassLoad
  13. JAVA分布式架构的演变及解决方案
  14. 【文章汇总】嵌入式Linux公众号
  15. wifi连接过程抓包
  16. 【毕业求职季】-听说你想去大厂看学妹,带你看看字节广告运营岗面试长啥样?
  17. Beetlsql自学笔记
  18. Android Exif 解析
  19. Unity RenderTexture实现 刮彩票、橡皮擦、擦除效果(3D物体)
  20. APP Launch 优化

热门文章

  1. WINDOWS文件夹下的应用程序
  2. 关心一下开放源码的许可证
  3. i7运行linux虚拟机会卡吗,i7 7200 linux 虚拟机
  4. 服务器主板北桥芯片组有哪些,主板上北桥芯片组都负责管理哪些硬件?
  5. win10命令行模式无法切换输入法
  6. (转)AndroidManifest 清单文件合并时出现 【quires a placeholder substitution but no value for is provided.】问题
  7. 联想st510开卡软件_无力吐槽的一单联想ST510固态硬盘数据恢复
  8. 优化算法—人工蜂群算法(ABC)
  9. Javaweb和微信小程序项目部署阿里云服务器总结(上)
  10. 手机有时触摸失灵解决方法