• Builder:

  《Effective Java》 第2条:遇到多个构造器参数时要考虑用构建器。

  建造者模式(Builder Pattern),也称生成器模式,定义如下:

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

  Separate the construction of a complex object from its representation so that the same construction process can create different representation.

  • 什么时候使用 Builder:

  我们常常会看见这种情况:我需要一个初始化一个复杂对象,在初始化的同时完成参数的赋值工作。

  • 数据模型:
@Data
@EqualsAndHashCode
@ToString
public class PolicyCommon { private String code;
private String category;
private String name;
private String inceptionDate; public PolicyCommon() {
super();
} public PolicyCommon(String code, String category, String name) {
super();
this.code = code;
this.category = category;
this.name = name;
}
}
  • 模型分析:

  PolicyCommon 带有4个参数,假定只有 inceptionDate不需要在创建的时候赋值。

  剩余3个参数参与初始化的工作,那么这个对象初始化之后的状态可能性为:2^3=8。

  • 传统的解决方案1——使用无参构造器,然后依次调用 set() 方法:
    @Test
void testPolicyCommon1() {
PolicyCommon policy = new PolicyCommon();
policy.setName("Gerrard");
policy.setCode("11123768");
policy.setCategory("Engineer");
System.out.println(policy);
}

  这种方法,将构造对象的过程拆分成多个动作,是存在风险的。

  因为对象不是一次性构造完成,使得对象在构造过程中存在状态不一致的情况。

  期间有 this 指针溢出的风险,阻碍了这个对象称为不可变对象的可能。在多线程条件下,需要额外的工作才能保证线程安全。

  • 传统的解决方案2——使用重叠参数的构造器:
    @Test
void testPolicyCommon2() {
PolicyCommon policy = new PolicyCommon("11123768", "Engineer", "Gerrard");
System.out.println(policy);
}

  这样做的劣势在于:

  1. 从调用者的角度来说,属性的意义不明显,很容易将参数位置颠倒了,但是编译器并没有报错,例如: new PolicyCommon("Engineer", "Gerrard", "11123768");
  2. 如果我只想初始化一个属性,如 code,那么构造器的调用会有许多冗余参数。例如:new PolicyCommon("11123768", null, null);
  • Builder 给出的解决方案:

  使用一个静态内部类 Builder,Builder 持有需要动态生成的属性。

  Builder 为每一个属性,提供 set() 方法,但是与通常的set() 方法不同,这些 set() 方法的返回值是 Builder 本身。

  Builder 提供一个 build() 方法,返回类型为外部类。

  外部类中,提供一个参数为 Builder 对象的构造器,且将其的权限设置为 private,如此一来,构造器的唯一途径就是 build() 方法。

  • 代码:
@Data
@EqualsAndHashCode
@ToString
public class PolicyBuilder { private String code;
private String category;
private String name;
private String inceptionDate; private PolicyBuilder(Builder builder) {
code = builder.code;
category = builder.category;
name = builder.name;
} public static class Builder { private String code;
private String category;
private String name; public Builder setCode(String code) {
this.code = code;
return this;
} public Builder setCategory(String category) {
this.category = category;
return this;
} public Builder setName(String name) {
this.name = name;
return this;
} public PolicyBuilder build() {
return new PolicyBuilder(this);
}
}
}
  • 调用 Builder:
    @Test
void testPolicyBuilder() {
PolicyBuilder policy = new PolicyBuilder.Builder().setName("Gerrard").setCode("11123768").build();
System.out.println(policy);
}

  可以看出,Builder 初始化的过程中,对参数选择更加自由,而且它不会使对象处于不同的状态。

  劣势在于冗长的内部类代码,以及构建过程中会增加一个 Builder 对象。

  • 使用 Lombok 一键 Builder:

  细心的朋友,在最初的 PolicyCommon 的数据模型中,会发现三个注解,这是 Lombok 框架的功能(org.projectlombok,License = MIT)。

  @Data,为类的每一个属性,自动生成 get() 和 set() 方法。

  @EqualsAndHashCode,为类生成 equals() 和 hashCode() 方法。

  @ToString,为类生成 toString() 方法。

  除此之外,Lombok 还提供了 @Builder 的注解,自动为类提供了 Builder 的功能。

  • Lombok Builder:
@Data
@EqualsAndHashCode
@ToString
public class PolicyBuilderLombok { private String code;
private String category;
private String name;
private String inceptionDate; @Builder
public PolicyBuilderLombok(String code, String category, String name) {
super();
this.code = code;
this.category = category;
this.name = name;
}
}
    @Test
void testPolicyBuilderLombok() {
PolicyBuilderLombok policy = new PolicyBuilderLombok.PolicyBuilderLombokBuilder()
.name("Gerrard").code("11123768").build();
System.out.println(policy);
}
  • 解析 @Builder:

  检查元注解:@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})

  这表明这个注解可以加在:类、构造器、方法(不推荐加在方法上)。

  @Builder 加在类上 <==> ,在类的全参构造器上加上 @Builder。

  @Builder 加在构造器上,这个构造器的入参就是内部类 Builder 的动态参数。

设计模式(四)建造者模式 Builder的更多相关文章

  1. 乐在其中设计模式(C#) - 建造者模式(Builder Pattern)

    原文:乐在其中设计模式(C#) - 建造者模式(Builder Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 建造者模式(Builder Pattern) 作者:webabc ...

  2. 二十四种设计模式:建造者模式(Builder Pattern)

    建造者模式(Builder Pattern) 介绍将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 示例用同样的构建过程创建Sql和Xml的Insert()方法和Get()方 ...

  3. 【设计模式】建造者模式 Builder Pattern

    前面学习了简单工厂模式,工厂方法模式以及抽象工厂模式,这些都是创建类的对象所使用的一些常用的方法和套路, 那么如果我们创建一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去做”,2 ...

  4. 设计模式之建造者模式——Builder

    一.概述 Builder模式,中文名为建造者模式,又名生成器模式.构建者模式等,是创建型设计模式之一.用于将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 1.适用性: 对象 ...

  5. Python 设计模式之建造者模式 Builder Pattern

    #引入建造者模式 肯德基的菜单上有 薯条, 鸡腿,鸡翅,鸡米花,可乐,橙汁,火腿汉堡,至尊虾汉堡,牛肉汉堡 , 鸡肉卷等这些单品,也有很多套餐. 比如 套餐1:鸡翅,至尊虾汉堡,可乐,薯条 套餐2:鸡 ...

  6. 设计模式-05建造者模式(Builder Pattern)

    1.模式动机 比如我们要组装一台电脑,都知道电脑是由 CPU.主板.内存.硬盘.显卡.机箱.显示器.键盘和鼠标组成,其中非常重要的一点就是这些硬件都是可以灵活选择,但是组装步骤都是大同小异(可以组一个 ...

  7. 设计模式之建造者模式(Builder)

    建造者模式原理:建造模式主要是用于产生对象的各个组成部分,而抽象工厂模式则用于产生一系列对象,建造者模式而且要求这些对象的组成部分有序. 代码如下: #include <iostream> ...

  8. 设计模式之建造者模式Builder(创建型)

    1. 概述 在软件开发的过程中,当遇到一个“复杂的对象”的创建工作,该对象由一定各个部分的子对象用一定的算法构成,由于需求的变化,复杂对象的各个部分经常面临剧烈的变化,但将它们组合在一起的算法相对稳定 ...

  9. 【UE4 设计模式】建造者模式 Builder Pattern

    概述 描述 建造者模式,又称生成器模式.是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 建造者模式将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无需知道复杂 ...

  10. 创建型设计模式之建造者模式(Builder)

    结构 意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 适用性 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 当构造过程必须允许被构造的对象有不 ...

随机推荐

  1. 手工恢复OSSIM数据库密码

    1,现象 今天需要远程连接ossim的mysql数据库读取些东西,于是登录ossim的终端,发现这个mysql客户端无法直接登录,使用自己安装时候那些口令都不行 alienvault:~# mysql ...

  2. Java 文件操作-RandomAccessFile

    1. RandomAccessFile     Java提供了一个可以对文件随机访问的操作,访问包括读和写操作.该类名为RandomAccessFile.该类的读写是基于指针的操作. 1)文件访问模式 ...

  3. python基础教程总结15——4 新闻聚合

    NNTP:网络新闻传输协议,Network News Transfer Protocol 目标: 从多种不同的来源收集新闻: 用户可以轻松添加新的新闻来源(甚至是新类型的新闻来源: 程序可以将编译好的 ...

  4. 四、filter和find函数的区别

    filter(): filter函数会返回data中为true那项的数组(即查询符合条件的数据) eg:data.filter((f)=>{ if(f[name]===item[name]){ ...

  5. 原型模式 -- JavaScript语言的灵魂

    原型模式就是将原型对象指向创建对象的类,使这些类共享原型对象的方法与属性.JS是基于原型链实现对象之间的继承,是对属性或者方法的共享,而不是对属性和方法的复制. // 图片轮播类 var LoopIm ...

  6. jQ实现JSON.stringify(obj)方法

    jQstringify是使用jQuery实现的JSON.stringify(obj)方法 代码如下:<script type="text/javascript" src=&q ...

  7. 用简单的语言描述C++ 是什么?

    用简单的语言描述C++ 是什么? 答:C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛.C++支持多种编程范式 --面向对象编程.泛型编程和过程化编程. 其编程领域众广,常用于系统开发,引 ...

  8. javaweb基础(16)_jsp指令

    一.JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定义了三个指令: pa ...

  9. java基础—抽象类介绍

    一.抽象类介绍

  10. mysql中影响数据库性能的因素讲解

    mysql中影响数据库性能的因素讲解 在本篇文章中我们给大家讲述了mysql中影响性能的因素以及相关知识点内容,有兴趣的朋友参考下 关于数据库性能的故事 面试时多多少少会讲到数据库上的事情,“你对数据 ...