建造器模式,是于创建带有大量参数的对象,并避免因参数数量多而产生的一些问题(如状态不一致-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. NPOI对Excel的操作(Sheet转DataTable、List<T>)

    通过NPOI对Excel进行操作,这里主要是读取的操作.封装到ExcelHelper操作类中. 1 using System.Collections.Generic; 2 using NPOI.HSS ...

  2. #一周五# (视频) 手掌四轴Estes 4606,树莓派2和WRTNode,WinHEC 2015深圳

    又到周五,本周<快速创建网站>系列接近尾声,主要部分已经完成,还差最后一篇博主我正在整理.这里给大家分享一些最近看到的有意思的东西. 手掌四轴飞行器 无人机这段时间可是大出风头,DJI或者 ...

  3. input 默认值为灰色,输入时清楚默认值

    input 默认值为灰色,输入时清楚默认值 <input value="please input your name" onFocus="if(value==def ...

  4. C#处理猜拳问题(非窗体)

    //猜拳,5局3胜,要求使用公用变量. namespace 结构体复习_公用变量 { class Program {public int rz=0; public int dz = 0; public ...

  5. Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排 ...

  6. 单表60亿记录等大数据场景的MySQL优化和运维之道

    此文是根据杨尚刚在[QCON高可用架构群]中,针对MySQL在单表海量记录等场景下,业界广泛关注的MySQL问题的经验分享整理而成,转发请注明出处. 杨尚刚,美图公司数据库高级DBA,负责美图后端数据 ...

  7. Linux系统管理命令之权限管理

    对于一个目录来说,x权限:可以cd进去 对于目录: 读:看 执行:进去 写:写操作 rw权限没有意义 umask 022     特殊权限: suid sgid 2种情况:对于文件:类似于suid对于 ...

  8. Linux下Awk详解(转载)

    什么是Awk Awk是一种小巧的编程语言及命令行工具.(其名称得自于它的创始人Alfred Aho.Peter Weinberger 和 Brian Kernighan姓氏的首个字母).它非常适合服务 ...

  9. BootStrap学习(2)

    使用Bootstrap添加代码框 可先看:简介.引入.包下载等:http://www.cnblogs.com/0201zcr/p/4900062.html Bootstrap 允许您以两种方式显示代码 ...

  10. JS MD5

    1 /* * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message * Digest Algorithm, as ...