Builder 模式的目的?

构造对象的方式过于复杂,不如将之抽离出来。比如,构造器参数过多

这样说也有点抽象,举个例子吧。

举个例子

比如 非常热门的消息队列RabbitMQAMQP.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
( contentType
contentEncoding,
//还有很多属性
);
}
}
}

分析

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 。

以上

java的设计模式 - Builder模式的更多相关文章

  1. java设计模式--Builder模式

    一.Builder模式 二.使用例子 三.Spring中的Builder模式 Builder模式,构建者.构造者模式,在<图解设计模式>中归为 生成实例 一栏,该模式用于组装具有复杂结构的 ...

  2. 设计模式-----Builder模式

    前言 近日,看到Myabtis中组件中SqlSessionFactory由SqlSessionFactoryBuilder().build()生成时,且采用Builder模式,遂记录学习之. SqlS ...

  3. Java 之 设计模式——代理模式

    设计模式——代理模式 一.概述 1.代理模式 (1)真实对象:被代理的对象 (2)代理对象:代理真实对象的 (3)代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 二.实现方式 1.静态代理 ...

  4. android 开发设计模式---Builder模式

    我们通过一个例子来引出Builder模式.假设有一个Person类,我们通过该Person类来构建一大批人,这个Person类里有很多属性,最常见的比如name,age,weight,height等等 ...

  5. 【java】使用Builder模式,轻松应对动态繁杂的方法参数

    背景:在咱编写的图片处理模块里,针对加载这个方法,参数很多,如: /** * 加载图片,经过内存.磁盘.两层缓存如果还没找到,则走http访问网络资源 * @param url 地址 * @param ...

  6. 设计模式-Builder模式(创建型模式)

    //以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Product.h #pragma once class Product { public: Product(); ~ ...

  7. Java中的Builder模式

    package com.mc.bsfram.others.entity; public class Person { private String name; private String addre ...

  8. java的设计模式 - 外观模式(Facade)

    目的 看脸模式目的很简单,就是给用户留个好印象,不想让用户关注系统中的具体细节,关注系统的外表(暴露出来的接口)就好了.一些 GUI 的菜单也好,SDK 也好或多或少也会用到这种思想.这更多的是一种思 ...

  9. Java与设计模式-策略模式

    在实际开发中,可能会遇到这样一个情况,某一功能的实现分为多种算法,这些算法能够认定为策略,在实际操作时选择不同算法或策略进行操作得出终于结果.在实际生活中.这些样例也是举不胜举.比如.商场举行活动,满 ...

随机推荐

  1. Vue 进阶之路(九)

    之前的文章我们介绍了 vue 中父组件之间的传值,本章我们再来看一下父子组件间传值的参数校验和非 Props 特性. <!DOCTYPE html> <html lang=" ...

  2. 鸟哥的Linux私房菜笔记第四章

    前言 对着<鸟哥的Linux私房菜-基础版>做了简化笔记.不想让自己知其然而不知其所然.所以写个博客让自己好好巩固一下,当然不可能把书中的内容全部写下来.在这里就简化一点把命令写下来. 让 ...

  3. 如何使用FluentMigrator进行数据库迁移

    标题:如何使用FluentMigrator进行数据库迁移 地址:https://www.cnblogs.com/lwqlun/p/10649949.html 作者: Lamond Lu FluentM ...

  4. 【反编译系列】一、反编译代码(dex2jar + jd-gui)和反编译资源(apktool)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! [反编译系列]二.反编译代码(jeb) [反编译系列]三.反编译神器(jadx) [反编译系列]四.反编译so文件(IDA_Pro) 概述 ...

  5. CopyOnWriteArrayList你都不知道,怎么拿offer?

    前言 只有光头才能变强 前一阵子写过一篇COW(Copy On Write)文章,结果阅读量很低啊...COW奶牛!Copy On Write机制了解一下 可能大家对这个技术比较陌生吧,但这项技术是挺 ...

  6. Asp.Net Core 轻松学-多线程之Task快速上手

    前言     Task是从 .NET Framework 4 开始引入的一项基于队列的异步任务(TAP)模式,从 .NET Framework 4.5 开始,任何使用 async/await 进行修饰 ...

  7. Python中最好用的命令行解析工具:argparse

    Python 做为一个脚本语言,可以很方便地写各种工具.当你在服务端要运行一个工具或服务时,输入参数似乎是一种硬需(当然你也可以通过配置文件来实现). 如果要以命令行执行,那你需要解析一个命令行参数解 ...

  8. SQL server脚本语句积累

    1:往现有的表中增加一个字段 IF NOT EXISTS ( SELECT 1 FROM sys.sysobjects so WITH ( NOLOCK ) INNER JOIN sys.syscol ...

  9. jQuery实现全选、反选和不选功能

    HTML 我们的页面上有一个歌曲列表,列出多行歌曲名称,并匹配复选框供用户选择,并且在列表下方有一排操作按钮. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 <ul id=&q ...

  10. iOS----------Runtime 获取属性列表 方法列表

    导入 #import <objc/runtime.h> unsigned int count; Method *methods = class_copyMethodList([UIAler ...