建造器模式,是于创建带有大量参数的对象,并避免因参数数量多而产生的一些问题(如状态不一致-JavaBean的setter模式)。

如果参数多且有些是必须初始化的,有些是不一定需要初始化的时候,创建对象是非常麻烦的,因为不得不为每种情况都添加一个构造方法。建造器模式,就是为了解决这个问题的。

使用Builder模式并不难:

1.创造一个静态内部建造类(Builder Class. e.g. UserBuilder)

2.类的构造方法必须设置为private,防止类被正常构造

3.建造类提供public方法,来设置可选的参数,并返回Builder对象

4.最后建造类提供build()方法,真正创建原来的类的对象

public class User {

    private final String firstName; // required
private final String lastName; // required
private final int age; // optional
private final String phone; // optional
private final String address; // optional private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
} // a list of getter method @Override
public String toString() {
return firstName + " " + lastName + "-" + age + " , " + phone + "/"
+ address;
} // Builder Class
public static class UserBuilder {
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address; public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
} public UserBuilder age(int age) {
this.age = age;
return this;
} public UserBuilder phone(String phone) {
this.phone = phone;
return this;
} public UserBuilder address(String address) {
this.address = address;
return this;
} public User build() {
return new User(this);
}
} public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(new User.UserBuilder("Jhon", "Doe").age(30)
.phone("1234567").address("Fake address 1234").build()
.toString());
}
}

另外,在build()方法里,也可以检验参数的正确性,例如:

public User build() {
User user = new user(this);
if (user.getAge()<120) {
throw new IllegalStateException(“Age out of range”); // thread-safe
}
return user;
}

这是线程安全的做法,因为user已经是不可变对象。下面的非线程安全做法,应该避免:

public User build() {
if (age 120) {
throw new IllegalStateException(“Age out of range”); // bad, not thread-safe
}
// This is the window of opportunity for a second thread to modify the value of age
return new User(this);
}

但是,这种建造器的使用方法,其实是有隐患的:

1. 它没有指引用户,一步步的进行构建对象;用户并不知道何时何地用何方法

2. 状态不一致的风险仍然存在

如果需要构建顺序的话,可以做如下修改,来使建造器模式更加人性化:

public class NewUser {

    private final String firstName; // required
private final String lastName; // required
private final int age; // optional
private final String phone; // optional
private final String address; // optional private NewUser(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
} // a list of getter method @Override
public String toString() {
return firstName + " " + lastName + "-" + age + " , " + phone + "/"
+ address;
} public static interface FirstNameStep {
LastNameStep firstName(String name);
} public static interface LastNameStep {
AgeStep lastName(String lastName);
} public static interface AgeStep {
PhoneStep age(int age);
} public static interface PhoneStep {
AddressStep phone(String phone);
} public static interface AddressStep {
BuildStep address(String address);
} public static interface BuildStep {
NewUser build();
} // Builder Class
public static class UserBuilder implements FirstNameStep, LastNameStep,
AgeStep, PhoneStep, AddressStep, BuildStep {
private String firstName;
private String lastName;
private int age;
private String phone;
private String address; private UserBuilder() {
} public static FirstNameStep newBuilder() {
return new UserBuilder();
} public LastNameStep firstName(String firstName) {
this.firstName = firstName;
return this;
} public AgeStep lastName(String lastName) {
this.lastName = lastName;
return this;
} public PhoneStep age(int age) {
this.age = age;
return this;
} public AddressStep phone(String phone) {
this.phone = phone;
return this;
} public UserBuilder address(String address) {
this.address = address;
return this;
} public NewUser build() {
return new NewUser(this);
}
} public static void main(String[] args) {
NewUser user = NewUser.UserBuilder.newBuilder().firstName("ABC")
.lastName("haha").age(10).phone("123").address("wa").build();
System.out.println(user.toString()); } }

这个实现更加复杂,利用了接口的设计,使得建造器创建对象时,可以一步接着一步(firstName->lastName->age->phone->address),相当友好。缺点是,实现有点复杂,代码量比较大。

参考:

http://www.javacodegeeks.com/2013/01/the-builder-pattern-in-practice.html

http://rdafbn.blogspot.ie/2012/07/step-builder-pattern_28.html

浅谈设计模式--建造器模式(Builder Pattern)的更多相关文章

  1. 浅谈设计模式--装饰者模式(Decorator Pattern)

    挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...

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

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

  3. 6. 星际争霸之php设计模式--建造器模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

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

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

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

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

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

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

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

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

  8. 浅谈设计模式-visitor访问者模式

    先看一个和visitor无关的案例.假设你现在有一个书架,这个书架有两种操作,1添加书籍2阅读每一本书籍的简介. //书架public class Bookcase { List<Book> ...

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

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

随机推荐

  1. 如何通过js跨域调用ASP.NET Web API (请问如何实现在javascript中通过http get的方式跨域调用ASP.NET Web API?)

    客户端js无需任何专门设置,使用通常的ajax调用即可: $.ajax({ url: '跨域URL', type: 'get', dataType: 'json', success: function ...

  2. Github入门(一)

    之前早就听说过Git的大名,但由于合作项目时的团体都非常小,所以一直没有开始系统的学习和使用(其实就是懒!),最近终于有动力开始进行入门的学习. 首先介绍一下自学用书:https://git-scm. ...

  3. spring filter过滤器

    1.简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 ...

  4. my_strcmp()

    void my_strcmp(const char* s1,const char* s2){ int i=0; while(*(s1+i)!='\0'||*(s2+i)!='\0'){ if(*(s1 ...

  5. 其他(一)Visual Studio 自动排版快捷键

    自动对齐快捷键为:ctrl+k+d 按快捷键前,请先将需要对齐的代码选中.不选中是不行的.

  6. TCMalloc:线程缓冲的Malloc

    这段时间比较闲,研究下内存管理,从官方文档开始啃起<TCMalloc : Thread-Caching Malloc>. 1.动机 TCMalloc要比glibc 2.3的malloc(可 ...

  7. python paramiko

    paramiko 遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接,可以实现远程文件的上传,下载或通过ssh远程执行命令. 项目地址:https://github.com/paramik ...

  8. 最短路问题Dijkstra算法

    Dijkstra算法可以解决源点到任意点的最短距离并输出最短路径 准备: 建立一个距离数组d[ n ],记录每个点到源点的距离是多少 建立一个访问数组v[ n ],记录每个点是否被访问到 建立一个祖先 ...

  9. 【2016-10-14】【坚持学习】【Day5】【策略模式】

    今天学了策略模式 例子 一个售票系统,针对不同的用户使用不用的计价方式, 环境类:一个业务场景(电影票累,) 抽象类:计价算法 具体实现类:5折算法,满100减20算法,..... 抽象策略类 abs ...

  10. AC日记——回文子串 openjudge 1.7 34

    34:回文子串 总时间限制:  1000ms 内存限制:  65536kB 描述 给定一个字符串,输出所有长度至少为2的回文子串. 回文子串即从左往右输出和从右往左输出结果是一样的字符串,比如:abb ...