一句话概括:私有化类的构造函数,并在类的内部添加用于实例化该类的建造者内部类。
当对象包含很多属性时,可以引入Builder模式来解决Factory和Abstract Factory设计模式中的一些问题。
当对象包含很多属性时,工厂模式或抽象工厂模式将有三个问题:
- 有太多的参数需要从client传递给工厂类容易出错,因为大多数时候参数的类型是相同的,所以很难维护参数的顺序以确保不出错。
- 一些参数可能是可选的,但在工厂模式中我们需要传递所有的参数,就是说那些可选的参数需要被置为NULL。
- 如果对象很重并且其创建过程很复杂,那么所有这些复杂性都将成为令人困惑的Factory类的一部分。
通过为构造函数提供所必需的参数,然后使用不同的setter方法来设置可选参数,这样我们可以解决大量参数的问题。 但这种方法的问题是,除非所有属性都被明确设置,否则对象状态将不一致,后面使用的时候通过接口抽象类等无法调用到被遗忘的参数。
构建者模式通过提供一种逐步构建对象并返回最终对象的方法来解决具有大量可选参数和状态不一致的问题。
Builder Design Pattern in Java
让我们看看如何用JAVA实现构建者模式
- 首先,需要创建一个静态嵌套类(static nested class),然后将所有参数从外部类复制到Builder类。 并且遵循命名约定,如果类名是Computer,那么builder类应该命名为ComputerBuilder。
- Java Builder类应该有一个public构造函数,其中将所有必需的属性作为参数。
- Java Builder类应该有设置可选参数的方法,并且在设置可选属性之后它应该返回相同的Builder对象。
- 最后一步是在构建器类中提供一个build()方法,该方法将返回client所需的对象。为此,我们需要在具有Builder类的外部类中定义私有构造函数,并把内部Builder类作为构造函数的参数。
示例代码:
public class Computer {
//required parameters
private String HDD;
private String RAM;
//optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public String getHDD() {
return HDD;
}
public String getRAM() {
return RAM;
}
public boolean isGraphicsCardEnabled() {
return isGraphicsCardEnabled;
}
public boolean isBluetoothEnabled() {
return isBluetoothEnabled;
}
//私有构造方法
private Computer(ComputerBuilder builder) {
this.HDD=builder.HDD;
this.RAM=builder.RAM;
this.isGraphicsCardEnabled=builder.isGraphicsCardEnabled;
this.isBluetoothEnabled=builder.isBluetoothEnabled;
}
//Builder Class, Computer的内部类
public static class ComputerBuilder{
// required parameters
private String HDD;
private String RAM;
// optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public ComputerBuilder(String hdd, String ram){
this.HDD=hdd;
this.RAM=ram;
}
//返回值为自己
public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled) {
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
return this;
}
//返回值为自己
public ComputerBuilder setBluetoothEnabled(boolean isBluetoothEnabled) {
this.isBluetoothEnabled = isBluetoothEnabled;
return this;
}
//构建实例
public Computer build(){
return new Computer(this);
}
}
}
注意Computer类只有getter方法,没有公共构造函数。 所以获得Computer对象的唯一方法是通过ComputerBuilder类。
下面是测试程序,用构建者类获取外部类的实例。
public class TestBuilderPattern {
public static void main(String[] args) {
//Using builder to get the object in a single line of code and
//without any inconsistent state or arguments management issues
Computer comp = new Computer.ComputerBuilder(
"500 GB", "2 GB").setBluetoothEnabled(true)
.setGraphicsCardEnabled(true).build();
}
}
一些JDK中的构建者模式应用
java.lang.StringBuilder#append() (unsynchronized非线程安全的)
java.lang.StringBuffer#append() (synchronized线程安全的)
String sample = new StringBuilder().append("aa").append("bb").append("cc").toString();
String sample2 = new StringBuffer().append("aa").append("bb").append("cc").toString();
总结
回顾开头提到的三个问题:当对象包含很多属性时,工厂模式或抽象工厂模式面临三个问题
1、有太多的参数需要从client传递给工厂类容易出错,因为大多数时候参数的类型是相同的,所以很难维护参数的顺序以确保不出错。
//在内部Builder类中,添加属性设置函数,并返回Builder本身
public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled) {
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
return this;
}
2、一些参数可能是可选的,但在工厂模式中我们需要传递所有的参数,就是说那些可选的参数需要被置为NULL。
//Builder Class, Computer的内部类
public static class ComputerBuilder{
//构造函数中仅包含所需的必选参数
public ComputerBuilder(必选参数){
}
//添加setter函数来设置可选参数
public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled){
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
return this;
}
}
3、如果对象很重并且其创建过程很复杂,那么所有这些复杂性都将成为令人困惑的Factory类的一部分。
//Builder Class, Computer的内部类
public static class ComputerBuilder{
//将复杂的创建过程封装在内部Builder类的Build方法中
public Computer Build(){
Computer computer = Computer(this);
//其它复杂的初始化操作
return computer
}
}
网友评论