模式动机

无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮、方向盘、发动机等各种部件。而对于大多数用户而言,无须知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一辆完整的汽车,可以通过建造者模式对其进行设计与描述,建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

在软件开发中,也存在大量类似汽车一样的复杂对象,它们拥有一系列成员属性,这些成员属性中有些是引用类型的成员对象。而且在这些复杂对象中,还可能存在一些限制条件,如某些属性没有赋值则复杂对象不能作为一个完整的产品使用;有些属性的赋值必须按照某个顺序,一个属性没有赋值之前,另一个属性可能无法赋值等。

复杂对象相当于一辆有待建造的汽车,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“外部化”到一个称作建造者的对象里,建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性以及它们的组装方式,这就是建造者模式的模式动机。

模式定义

造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式属于对象创建型模式。根据中文翻译的不同,建造者模式又可以称为生成器模式。

示例

在Effective Java第二版中,Josh Bloch在第二章中就提到使用Builder模式处理需要很多参数的构造函数。他不仅展示了Builder的使用,也描述了相这种方法相对使用带很多参数的构造函数带来的好处。需要指出的是Josh Bloch已经在他的书本贯穿了这一思想。

标准Builder

Person.java

package com.ricky.builder.ch1;/*** ${DESCRIPTION}** @author Ricky Fung* @create 2016-07-06 16:39*/
public class Person {private final String firstName;private final String lastName;private final String middleName;private final int age;private final String street;private final String district;private final String city;private final String province;private final boolean isFemale;private final boolean isEmployed;public Person(String firstName, String lastName, String middleName, int age, String street,String district, String city, String province, boolean isFemale, boolean isEmployed) {this.firstName = firstName;this.lastName = lastName;this.middleName = middleName;this.age = age;this.street = street;this.district = district;this.city = city;this.province = province;this.isFemale = isFemale;this.isEmployed = isEmployed;}@Overridepublic String toString() {return "Person{" +"firstName='" + firstName + '\'' +", lastName='" + lastName + '\'' +", middleName='" + middleName + '\'' +", age=" + age +", street='" + street + '\'' +", district='" + district + '\'' +", city='" + city + '\'' +", province='" + province + '\'' +", isFemale=" + isFemale +", isEmployed=" + isEmployed +'}';}
}

PersonBuilder

package com.ricky.builder.ch1;/*** ${DESCRIPTION}** @author Ricky Fung* @create 2016-07-06 16:40*/
public class PersonBuilder {private String firstName;private String lastName;private String middleName;private int age;private String street;private String district;private String city;private String province;private boolean isFemale;private boolean isEmployed;public PersonBuilder(){}public PersonBuilder firstName(String firstName) {this.firstName = firstName;return this;}public PersonBuilder lastName(String lastName) {this.lastName = lastName;return this;}public PersonBuilder middleName(String middleName) {this.middleName = middleName;return this;}public PersonBuilder age(int age) {this.age = age;return this;}public PersonBuilder street(String street) {this.street = street;return this;}public PersonBuilder district(String district) {this.district = district;return this;}public PersonBuilder city(String city) {this.city = city;return this;}public PersonBuilder province(String province) {this.province = province;return this;}public PersonBuilder isFemale(boolean isFemale) {this.isFemale = isFemale;return this;}public PersonBuilder isEmployed(boolean isEmployed) {this.isEmployed = isEmployed;return this;}public Person create() {return new Person(firstName, lastName, middleName, age, street, district, city, province, isFemale, isEmployed);}
}
package com.ricky.builder;import com.ricky.builder.ch1.Person;
import com.ricky.builder.ch1.PersonBuilder;/*** ${DESCRIPTION}** @author Ricky Fung* @create 2016-07-06 16:41*/
public class PersonBuilderDemo {public static void main(String[] args){Person person = new PersonBuilder().firstName("ricky").lastName("fung").age(27).street("建国路").district("朝阳").city("北京市").province("北京").isFemale(false).isEmployed(true).create();System.out.println(person);}
}

静态内部类

SIAMessage.java

package com.ricky.builder.ch2;/*** ${DESCRIPTION}** @author Ricky Fung* @create 2016-07-06 13:19*/
public class SIAMessage {private final String businessCode;private final String type;private final String message;private final int timeout;SIAMessage(String businessCode, String type, String message, int timeout) {this.businessCode = businessCode;this.type = type;this.message = message;this.timeout = timeout;}public static Builder custom(){return new Builder();}public String getBusinessCode() {return businessCode;}public String getType() {return type;}public String getMessage() {return message;}public int getTimeout() {return timeout;}public static class Builder {private String businessCode;private String type;private String message;private int timeout;public Builder setBusinessCode(String businessCode) {this.businessCode = businessCode;return this;}public Builder setType(String type) {this.type = type;return this;}public Builder setMessage(String message) {this.message = message;return this;}public Builder setTimeout(int timeout) {this.timeout = timeout;return this;}public SIAMessage build() {initDefaultValue(this);return new SIAMessage(businessCode, message, type, timeout);}private void initDefaultValue(Builder builder) {if(builder.businessCode==null || builder.businessCode.length()<1){throw new IllegalArgumentException("businessCode  can not be empty!");}if(builder.message==null || builder.message.length()<1){throw new IllegalArgumentException("message can not be empty!");}if(builder.type==null || builder.type.length()<1){  //设置默认mime-typebuilder.type = "application/json";}if(builder.timeout<1){builder.timeout = 6*1000;}}}@Overridepublic String toString() {return "SIAMessage{" +"businessCode='" + businessCode + '\'' +", type='" + type + '\'' +", message='" + message + '\'' +", timeout=" + timeout +'}';}}

客户端调用

package com.ricky.builder;import com.ricky.builder.ch2.SIAMessage;/*** ${DESCRIPTION}** @author Ricky Fung* @create 2016-07-06 13:22*/
public class SIAMessageDemo {public static void main(String[] args){//1.SIAMessage message = new SIAMessage.Builder().setBusinessCode("yrd").setMessage("hello world").setTimeout(1000).build();System.out.println(message);//2.message = SIAMessage.custom().setBusinessCode("yrd").setMessage("hello world").setTimeout(1000).build();System.out.println(message);}
}

复杂的Builder

Builder嵌套

package com.ricky.builder.ch3;/*** ${DESCRIPTION}** @author Ricky Fung* @create 2016-07-06 15:38*/
public class Car {private final String manufacturer;    //制造商private final String brand;   //品牌private final String model;   //型号private final String producingArea;   //产地private final String producingDate;   //生产时间private final Engine engine;private final Wheel wheel;private final Light light;Car(String manufacturer, String brand, String model, String producingArea,String producingDate, Engine engine, Wheel wheel, Light light) {this.manufacturer = manufacturer;this.brand = brand;this.model = model;this.producingArea = producingArea;this.producingDate = producingDate;this.engine = engine;this.wheel = wheel;this.light = light;}public static class Builder{private String manufacturer;    //制造商private String brand;   //品牌private String model;   //型号private String producingArea;   //产地private String producingDate;   //生产时间private Engine engine;private Wheel wheel;private Light light;public Builder(String manufacturer, String brand, String model) {this.manufacturer = manufacturer;this.brand = brand;this.model = model;}public Builder producingArea(String producingArea){this.producingArea = producingArea;return this;}public Builder producingDate(String producingDate){this.producingDate = producingDate;return this;}public Builder engine(Engine engine){this.engine = engine;return this;}public Builder wheel(Wheel wheel){this.wheel = wheel;return this;}public Builder light(Light light){this.light = light;return this;}public Car build(){return new Car(manufacturer, brand, model, producingArea, producingDate, engine, wheel, light);}}
}
package com.ricky.builder.ch3;/*** 汽车发动机** @author Ricky Fung* @create 2016-07-06 15:42*/
public class Engine {private final String pl;  //排量private final String maxOutputPower; //最大输出功率private final int rpm;  //转速Engine(String pl, String maxOutputPower, int rpm) {this.pl = pl;this.maxOutputPower = maxOutputPower;this.rpm = rpm;}public static Builder custom(){return new Builder();}public static class Builder{private String pl;  //排量private String maxOutputPower; //最大输出功率private int rpm;  //转速public Builder pl(String pl){this.pl = pl;return this;}public Builder maxOutputPower(String maxOutputPower){this.maxOutputPower = maxOutputPower;return this;}public Builder rpm(int rpm){this.rpm = rpm;return this;}public Engine build(){return new Engine(pl, maxOutputPower, rpm);}}
}
package com.ricky.builder.ch3;/*** 汽车轮子** @author Ricky Fung* @create 2016-07-06 15:40*/
public class Wheel {private String brand;private String producingDate;Wheel(String brand, String producingDate) {this.brand = brand;this.producingDate = producingDate;}public static Builder custom(){return new Builder();}public static class Builder{private String brand;private String producingDate;public Builder brand(String brand){this.brand = brand;return this;}public Builder producingDate(String producingDate){this.producingDate = producingDate;return this;}public Wheel build(){return new Wheel(brand, producingDate);}}
}
package com.ricky.builder.ch3;/*** 车灯** @author Ricky Fung* @create 2016-07-06 15:43*/
public class Light {private String brand;private String structure;   //结构private String producingDate;Light(String brand, String structure, String producingDate) {this.brand = brand;this.structure = structure;this.producingDate = producingDate;}public static Builder custom(){return new Builder();}public static class Builder{private String brand;private String structure;   //结构private String producingDate;public Builder brand(String brand){this.brand = brand;return this;}public Builder structure(String structure){this.structure = structure;return this;}public Builder producingDate(String producingDate){this.producingDate = producingDate;return this;}public Light build(){return new Light(brand, structure, producingDate);}}
}

客户端调用

package com.ricky.builder;import com.ricky.builder.ch3.Car;
import com.ricky.builder.ch3.Engine;
import com.ricky.builder.ch3.Light;
import com.ricky.builder.ch3.Wheel;/*** 汽车组装** @author Ricky Fung* @create 2016-07-06 15:59*/
public class CarDemo {public static void main(String[] args){Car car = new Car.Builder("Audi", "奥迪", "Q5").producingArea("中国大陆").producingDate("2016-07-01 00:00:00").engine(Engine.custom().pl("2L").maxOutputPower("110kW").rpm(5400).build()).wheel(Wheel.custom().brand("AA").producingDate("2016-03-01 00:00:00").build()).light(Light.custom().brand("5A").structure("隔热玻璃").producingDate("2016-02-01 00:00:00").build()).build();System.out.println(car);}
}

优缺点

优点

  • 在建造者模式中, 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
  • 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,
    用户使用不同的具体建造者即可得到不同的产品对象。
  • 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
  • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。

缺点

  • 使用Builder模式是肯定会增加代码量的。此外,尽管客户端的代码可读性明显改善,但随之而来的客户端代码变得更加冗长。
  • Builder会增加个类代码,这也意味着开发者在给类增加属性时有时会忘记给该属性添加支持的builder。

参考资料

http://www.importnew.com/6605.html
https://github.com/iluwatar/java-design-patterns

Builder模式总结相关推荐

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

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

  2. Creational模式之Builder模式

    1.意图 将一个复杂对象的构建与它表示分离,使得相同的构建过程能够创建不同的表示. 查看很多其它请点击 2.别名 无 3.动机 一个RTF(Rich Text Format)文档交换格式的阅读器应能将 ...

  3. 可扩展性的builder模式的构建方法

    http://www.cnblogs.com/happyhippy/archive/2010/09/01/1814287.html 使用builder模式的时候: 本篇文章的原因:builder模式接 ...

  4. GOF对Builder模式的定义(转载)

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

  5. 创建型模式之Builder模式

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

  6. java设计模式:Builder模式

    Builder模式关键是在建立对象是一步一步处理 package customer;class Starbucks {private String size;private String drink; ...

  7. JAVA Builder模式构建MAP/LIST的示例

    我们在构建一个MAP时,要不停的调用put,有时候看着觉得很麻烦,刚好,看了下builder模式,觉得这思路不错,于是乎,照着用builder模式写了一个构建MAP的示例,代码如下: import j ...

  8. 设计模式-Builder模式

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

  9. Intellij idea generate builder 插件-用于自动生成builder模式代码

    2019独角兽企业重金招聘Python工程师标准>>> 目的:开发中喜欢builder模式去构造一个实例,而当一个对象的属性过多的时候,手动的去完成一个类的builder是很繁琐的: ...

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

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

最新文章

  1. Java 编程开始啦
  2. 可以直接用的“ html转字符串string”方法
  3. linux signal 符号表,铁路信号图形符号
  4. Angular 服务器端渲染的学习笔记(一)
  5. SAP Spartacus MyCompany菜单里Org unit的Add按钮Accessibility问题初始分析
  6. 在程序员面前千万不要说这9句话,我一个同事就死的很惨!
  7. Java EE,Gradle和集成测试
  8. Map排序,获取map的第一值,根据value取key等操作(数据预处理)
  9. mysql中怎么存住文件链接_数据库如何保存链接文件
  10. C#中通过Lambda表达式为委托传入更多的参数
  11. zngnqfxtuubuosmo
  12. SecureCRT上传下载位置
  13. python调用函数出现未定义_在python中调用函数时出错“函数未定义”
  14. 【推荐】“汇新杯”新兴科技+互联网创新大赛——IT人大展拳脚的创业大赛
  15. unity3D原生声音系统
  16. 重磅成果丨ASAM SOVD 1.0.0正式发布
  17. 程序员日常照片大合集!快来大饱眼福!
  18. 小目标检测算法SNIPER—— SNIP的实战版本 (目标检测)(two-stage)(深度学习)(Arvix 2018)
  19. 电脑备份数据怎么备份?
  20. Proxy returns “HTTP/1.1 407 Proxy Authentication Required

热门文章

  1. 基于css的表单模板
  2. 将excel表格数据转换为xml文本数据
  3. ls -l 字段意思
  4. ZOJ--1005:Jugs(dfs)
  5. 安装方式B--使用ClouderaManager的Parcels包进行安装
  6. 【TRIO-Basic从入门到精通教程十六】UDP通讯测试补充
  7. redis启动、关闭命令
  8. 米老师解惑----1
  9. Qt error: /usr/bin/ld: cannot find -lGL: No such file or directory
  10. Kubernetes1.13集群安装dashboard 1.10.1