建造器模式,是于创建带有大量参数的对象,并避免因参数数量多而产生的一些问题(如状态不一致-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

最新文章

  1. 深入学习jQuery元素过滤
  2. poj 1328 Radar Installation
  3. bootstrap datetimepicker时间日期控件
  4. Winform ListView 元素拖动
  5. [LOJ 1027] Dangerous Maze
  6. [python]使用ElementTree解析XML【译】
  7. mysql导出数据库几种方法
  8. 转 jQuery(图片、相册)插件代码实例
  9. 解析jQuery中extend方法--用法《一》
  10. idea Empty git --version output:解决
  11. RabbitMQ安装,Windows下
  12. 在app中从下向上滑动,以找到不在默认第一页的元素
  13. 关于NB-IoT的十大问题和答案【转】
  14. ORACLE 根据 sql_id 查询绑定变量的传入值
  15. photoshop学习2
  16. 两个类似的ViewModel一个可以重写事件,另一个不能重写事件,是哪里出了错。
  17. UI5-文档-4.7-JSON Model
  18. LeetCode: Letter Combinations of a Phone Number 解题报告
  19. java并发编程:线程安全管理类--原子操作类--AtomicIntegerArray
  20. Js 中实现重定向的几种方式

热门文章

  1. PHP操作mysql数据库:[2]查询数据听语音
  2. 基于微软平台IIS/ASP.NET开发的大型网站有哪些?
  3. PHP implode() 函数 把数组元素组合为字符串
  4. junit 使用
  5. Chrome浏览器二维码生成插件
  6. JavaScript Lib Interface (JavaScript系统定义的接口一览表)
  7. 《java JDK7 学习笔记》课后练习题3
  8. win8.1 user profile service 服务登录失败
  9. Linux 下从头再走 GTK+-3.0 (一)
  10. IO的多路复用和信号驱动