您的位置:首页 > 产品设计 > UI/UE

浅谈设计模式--建造器模式(Builder Pattern)

2014-02-05 17:38 417 查看
建造器模式,是于创建带有大量参数的对象,并避免因参数数量多而产生的一些问题(如状态不一致-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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: