1、经典的Builder模式
Product

/**
* 计算机抽象类, 即Product角色
*/
public abstract class Computer {
protected String mBoard;
protected String mDisplay;
protected String mOS;
public Computer() {
}
public void setBoard(String board) {
mBoard = board;
}
public void setDisplay(String display) {
mDisplay = display;
}
public abstract void setOS();
@Override
public String toString() {
return "Computer{"
+ "mBoard='"
+ mBoard
+ '\''
+ ", mDisplay='"
+ mDisplay
+ '\''
+ ", mOS='"
+ mOS
+ '\''
+ '}';
}
}
复制代码
作者:mundane
链接:https://juejin.im/post/5aa3dfd66fb9a028c42dd13a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
具体的Product

/**
* 具体的Computer类
*/
public class Macbook extends Computer {
public Macbook() {
}
@Override
public void setOS() {
mOS = "Mac OS X 10.10";
}
}
作者:mundane
链接:https://juejin.im/post/5aa3dfd66fb9a028c42dd13a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
抽象Builder
/**
* 抽象Builder类
*/
public abstract class Builder {
public abstract void buildBoard(String board);
public abstract void buildDisplay(String display);
public abstract void buildOS();
public abstract Computer create();
}
作者:mundane
链接:https://juejin.im/post/5aa3dfd66fb9a028c42dd13a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
ConcreteBuilder
/**
* 具体的Builder类, MacbookBuilder
*/
public class MacbookBuilder extends Builder {
private Computer mComputer = new Macbook();
@Override
public void buildBoard(String board) {
mComputer.setBoard(board);
}
@Override
public void buildDisplay(String display) {
mComputer.setDisplay(display);
}
@Override
public void buildOS() {
mComputer.setOS();
}
@Override
public Computer create() {
return mComputer;
}
}
复制代码
作者:mundane
链接:https://juejin.im/post/5aa3dfd66fb9a028c42dd13a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/**
* Director类, 负责构造Computer
*/
public class Director {
Builder mBuilder;
public Director(Builder builder) {
mBuilder = builder;
}
public void construct(String board, String display) {
mBuilder.buildBoard(board);
mBuilder.buildDisplay(display);
mBuilder.buildOS();
}
}
作者:mundane
链接:https://juejin.im/post/5aa3dfd66fb9a028c42dd13a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
public class Main {
public static void main(String[] args) {
Builder builder = new MacbookBuilder();
Director pcDirector = new Director(builder);
pcDirector.construct("英特尔主板", "Retina 显示器");
Computer macBook = builder.create();
System.out.println("Computer Info: " + macBook.toString());
}
}
作者:mundane
链接:https://juejin.im/post/5aa3dfd66fb9a028c42dd13a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
输出结果:
Computer Info: Computer{mBoard='英特尔主板', mDisplay='Retina 显示器', mOS='Mac OS X 10.10'}
可以看出, 经典的 Builder 模式重点在于抽象出对象创建的步骤,并通过调用不同的具体实现类从而得到不同的结果, 但是在创建过程中依然要传入多个参数, 不是很方便, 所以有了变种的Builder模式
2、变种的Builder模式
public class User {
private final String firstName; // 必传参数
private final String lastName; // 必传参数
private final int age; // 可选参数
private final String phone; // 可选参数
private final String address; // 可选参数
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
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);
}
}
}
使用new User.UserBuilder("王", "小二")
.age(20)
.phone("123456789")
.address("亚特兰蒂斯大陆")
.build();
唯一可能存在的问题就是会产生多余的Builder对象,消耗内存。然而大多数情况下我们的Builder内部类使用的是静态修饰的(static),所以这个问题也没多大关系。
由于Builder是非线程安全的,所以如果要在Builder内部类中检查一个参数的合法性,必需要在对象创建完成之后再检查。
public User build() {
User user = new user(this);
if (user.getAge() > 120) {
throw new IllegalStateException(“Age out of range”); // 线程安全
}
return user;
}
上面的写法是正确的,而下面的代码是非线程安全的:
public User build() {
if (age > 120) {
throw new IllegalStateException(“Age out of range”); // 非线程安全
}
return new User(this);
}
