上一次说到工厂模式是因为在java多态中避免违背单一职责和开闭原则产生的设计模式。今天的这个建造者模式同样作为创造性(creational patterns) 的设计模式, 当我们的系统足够复杂的时候,我们类会变多,同时类所承担的功能也在增多。基于此我们可能会碰到一个复杂的类去实例化成为有不同结构或者内部状态的实例对象,我们可以独立的类去概括这个实例逻辑。这些类被称为”建造者(builder)。
当然定义还是挺绕口的,我们上图:
建造者模式仍然遵从单一职责和开闭原则,我们把复杂对象实例化的逻辑放在builder中,如果我们需要不同结构的实例,我们可以增加builder,也就是builder的单一职责就是建造复杂对象实例,同时新增的话可以但是不能对原有的builder修改。我们举一个例子,比如造车,全民造车。
如果造车是个很复杂的工程,假如车这个类很复杂,当然如果我们需要不同类型的实例化他也复杂,我们可以用不同的构造方法去实现,但是如果参数很多,可选的参数也很多,会让我们的类复杂度膨胀。使用set get是另外一个选择,但是在构造属性的过程中容易状态变化,或者我们就单纯的set错了,就很麻烦。所以我们就把实例化的逻辑抽出来使用我的builder去代替。
总体如下,这是一个经典的builder的结构图。Director决定构建哪一个产品比如电动车或者燃油车;CarBuilder是Builder的基类,内含四个抽象方法,因为车的构成不一样,所以一般来说把不相同的或者可选的参数抽出来。就车的概念来说,一般来说引擎(Engine),轮子(Wheel),传送装置/变速箱(Transmission),颜色(paint),是必要的,因为不论是电动车,混动车或燃油车都是需要如此几个构建的,我们可以放在具体的类里面的构造方法,避免构造方法过于复杂和难扩展。所以四个抽象方法是buildCar, addGasTank, addBatteries, getCar,选配组件或者差异组件可以为空或者抛出异常。
其实director在大部分情况下可以省去,这样就构成了简单建造者方法,client也就是客户打交道可以直接跟CarBuilder去打交道。
同时既然我们的直觉是使用构造函数去增加我们可选参数,在《Effective Java》这本书中作者Google的首席java架构:Joshua Bloch,提出了一个更简洁有效的处理方式,使用java内部类和“方法链”(Method chaining)去替代多个构造方法或者构造器。方法链是一种返回当前对象的方式,这样就可以链式的连接和调用。
举个例子:
public Builder setColour(String colour){
this.colour = colour;
return this;
}
这样我们可以完成一个调用链路:
builder.setColour("blue")
.setEngine("V8")
.setGasTank("100L")
.setTransmission("auto")
.build();
这样就意味着我们的代码更简单了,甚至只需要Car这一个类:
public class Car{
private String paint;
private String wheel;
private String engine;
private String transmission;
private String gasTank;
private String batteries;
private Car(CarBuilder builder){
this.paint = builder.paint;
this.wheel = builder.wheel;
this.engine = builder.engine;
this.transmission = builder.transmission;
this.gasTank = builder.gasTank;
this.batteries = builder.batteries;
}
public static class CarBuilder{
private String paint;
private String wheel;
private String engine;
private String transmission;
private String gasTank;
private String batteries;
private CarBuilder(String paint, String wheel, String engine, String transmission){
this.paint = paint;
this.wheel = wheel;
this.engine = engine;
this.transmission = transmission;
}
public CarBuilder setGasTank(String gasTank){
this.gasTank = gasTank;
return this;
}
public CarBuilder setBatteries(String batteries){
this.batteries = batteries;
return this;
}
public Car build(){
return new Car(this);
}
//get methods omitted
}
然后就是我们链路调用发挥的时候了:
Car car = new Car.CarBuilder("blue","steel wheels","V8","auto")
.setGasTank("100L")
.setBatteries("BYD16")
.build();
这里就叙述完了,其实在JDK中会有使用到建造者模式的,比如我们熟知的StringBuilder就是在append方法中使用了
public StringBuilder append(StringBuilder sb){
super.append(sb);
return this;
}