Builder 模式的目的?

构造对象的方式过于复杂,不如将之抽离出来。比如,构造器参数过多
这样说也有点抽象,举个例子吧。

举个例子

比如 非常热门的消息队列RabbitMQ 的 AMQP.BasicProperties

因为它的属性比较多,所以构造函数也是挺吓人的。

我看到也不太想调用。
如果现在要构造一条消息

  • 投递模式(delivery mode)为 2
  • 优先级(priority)是 2
  • content-type 为 text/plain

在没有 builder 模式之前,是这样构造的

new AMQP.BasicProperties("text/plain",null,null,2,1,null,null,null,null,null,null,null,null,null);

痛苦啊!!!不信,你自己也可以尝试构造一下。

  • 构造函数有很多你不想设置的参数
  • 你要看准,哪个参数要赋值,哪个参数不赋值,一不小心就可能出错了。而这里有 14 个参数。。。
  • 维护性差,写完代码再看一下,也看不出这个参数究竟是什么意思。还要点进去,一个一个参数地看才知道是什么意思

而用了 Builder 模式后。

new AMQP.BasicProperties.Builder().contentType("text/plain").deliveryMode(2).priority(1).build();

舒畅!!!

Builder 是如何实现?

很简单。

  • BasicProperties中添加一个叫Builder的内部类
  • Builder 中所有字段和BasicProperties类是完全一致的
  • Builder实例在调用build函数的时候,再调用BasicProperties的构造函数构造对象。

代码如下

public static class BasicProperties{private String contentType;private String contentEncoding;private Map<String,Object> headers;private Integer deliveryMode;private Integer priority;//... 还有很多属性public BasicProperties(String contentType,String contentEncoding,Map<String,Object> headers,Integer deliveryMode,//...String clusterId){this.contentType = contentTypel;this.contentEncoding = contentEncoding;//...}public static final class Builder {private String contentEncoding;private Map<String,Object> headers;private Integer deliveryMode;private Integer priority;//.. 和BasicProperties的字段一致的。public Builder contentType(String contentType){this.contentType = contentType; return this; }public Builder contentEncoding(String contentEncoding){this.contentEncoding = contentEncoding; return this; }public BasicProperties build() {return new BasicProperties( contentTypecontentEncoding,//还有很多属性);}}
}

分析

Builder 模式的好处

  • 不用花太多心思去记构造器的顺序,在 ide 中输入一个点就有自动提示了
  • 好维护,很容易看到看明白这是什么属性

坏处

  • 构造对象就要先调用 Buidler 构造器,多了构造器的开销
  • 类的关系变得复杂了

其他的做法

如果不用 Builder 模式,有其他的做法吗?

重叠构造器?

比如,上面的例子,我构造的消息只需 投递模式(delivery mode)、优先级(priority)、 content-type ,专门为这几个参数弄个专门的构造函数,可以吗?
调用就变成这样了。

new AMQP.BasicProperties("text/plain",2,1)

可以,

  • 但依然不太好看。
  • 如果有不同的需求,各种属性都排列组合一下也麻烦。
  • 不实际,因为类字段的类型可能会是一样的,有些组合注定不行

javaBean 模式呢?

BasicProperties  p = new AMQP.BasicProperties();
p.setContentType("text/plain");
p.setDeliveryMode(2);
p.setPriority(1);

在《effective java》中就探讨过这个可能,书中是这样说的

因为构造过程被分到几个调用中,在构造过程中 javaBean 可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。试图使用处于不一致状态的对象,将导致失败,这种失败与包含错误的代码大相径庭,因此它调试起来十分困难。与此相关的另一点不足在于,javaBeans 模式阻止了把类做成不可变的可能,这需要程序员付出格外的努力来确保它的线程安全。

这话就有点摸不着头脑,什么意思

其实意思是大概的,

  1. javaBean 是构造与字段赋值分离的,有可能 线程 1 在给对象 Obj 赋值,还没有赋完成的时候,线程 2 就拿了 Obj 的值了,就不一致了
  2. 如果 Obj 的字段全都是 final 的,不会出现上面那种情况,但字段只能会通过构造函数赋值(builder 模式也行),不能使用 javaBeans 的 setXXX 函数赋值了。
  3. 对多线程要求的,比如是传给消息队列的对象,程序员要保证下线程安全。
  4. 这也是个一个开放开闭的问题,Javabean 这样的写法确实和完全开放没啥区别,如果字段确定下来不用改了就最好设为 final 。

以上

转载于:https://www.cnblogs.com/jojo-feed/p/10155214.html

java的设计模式 - Builder模式相关推荐

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

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

  2. 设计模式-Builder模式

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

  3. Java常用设计模式————原型模式(一)

    介绍 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 原型模式用于创建重复的对象,同时又能保证性能.当直接创建对象的代价比较大时,则采用 ...

  4. 设计模式--builder 模式

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

  5. Java 有限状态机 (设计模式——状态模式)

    Java 有限状态机 (设计模式--状态模式) 编写代码的时候,有时会遇见较为复杂的swith...case...和if...else...语句.这一刻有时会想到状态机,用有限状态机替换swith.. ...

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

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

  7. Java设计模式-Builder模式

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

  8. 设计模式 —— Builder 模式

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

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

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

最新文章

  1. 通过StringBuilder的reverse()实现倒序
  2. Java并发基础:了解无锁CAS就从源码分析 1
  3. 【Cockpit】 如何组织管理多台服务器?
  4. Linux环境部署jenkins
  5. 全球及中国汽车轮胎再制造市场销售产值与运营发展模式分析报告2022年
  6. 小议IndexedDB中的主要对象
  7. SectionIndexer中的getSectionForPosition()与getPositionForSection()解惑
  8. it 部门的建议_应对IT项目阻力的8个建议
  9. postgresql,pgadmin4安装后出错,界面只有文字
  10. zabbix添加表达式
  11. Win10系统如何解除U盘写保护模式
  12. 实时计算storm流程架构总结
  13. Android Studio快捷键-mac版
  14. 使用pyqt开发gui(pyqt集成到pycharm)
  15. Android ImageSwitcher 配合Picasso解决内存溢出(OOM)问题
  16. uniapp本地开发小程序代码超过2M,不能预览和真机调试解决办法
  17. 端口扫描之FTP反弹扫描
  18. shanzhi -接小球游戏2.0
  19. 奶油面膜行业调研报告 - 市场现状分析与发展前景预测
  20. 添加账号Linux命令,linux使用useradd命令添加用户

热门文章

  1. 理论上每天有8.5到11.5小时的学习时间,可是为什么只有最多4小时是有效的?如何改善?...
  2. 从OpenStack Newton发布看开源云计算
  3. composer 报 zlib_decode(): data error
  4. WIN API当中的堆管理,虚拟内存及常规复制,移动,填充代码
  5. 改变QTableWidget 行高
  6. linux find 命令详解
  7. 如何学好C、C++------思维方式的转变
  8. Java经典面试题(N人循环报M个数出列)实现
  9. 宿主机windows Xp部署virtualBox虚拟机并在其上安装linux ubuntu操作系统
  10. 关于mysql数据库中存放中文字段乱码问题解决方案