建造者模式 Builder Pattern
创建型模式:关注对象的创建过程,它描述如何将对象的创建、使用分离,让用户无需关心对象的创建细节,从而降低系统的耦合度,让设计方案易于修改、扩展。
一、概述
建造者模式(Builder Pattern,生成器模式):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
二、结构
- Builder(抽象建造者):
创建产品对象部件的指定抽象接口,在接口中声明构建各种部件(属性)的方法,与返回复杂对象的方法。 - ConcreteBuilder(具体建造者):
实现了 Builder 接口,实现了各个部件的具体构造和装配方法,定义并明确创建的复杂对象,也可以由它提供一个方法返回复杂对象。 - Product(产品):
被构建的复杂对象,包含多个组成部件,具体建造者创建该产品内部,并定义装配过程。 - Director(指挥者):
又称 导演类,负责安排复杂对象的构建次序,指挥者与抽象建造者之间的存在关系,通过 construct() 方法调用部件构造、装配方法,完成建造。可以通过反射、配置文件实现,灵活建造者可省去指挥者,但用户须为部件构建方法传入合适的参数。
三、举例实现
实例代码:
Product(产品):
public class Car {
//定义部件,可以是值类型 / 引用类型
private String engine; //引擎
private String wheel; //轮胎
private String accelerator; //油门
private String clutch; //离合器
private String shiftGear; //变速器
private String breakSys; //刹车系统
private String shell; //外壳
private String fuelTank; //燃油箱
private String seat; //座椅
/*
* 省略所有属性的 Setter、Getter 方法
*/
}
Builder(抽象建造者):
public abstract class CarBuilder {
//创建产品对象
protected Car car = new Car();
public abstract void buildEngine();
public abstract void buildWheel();
public abstract void buildAccelerator();
public abstract void buildClutch();
public abstract void buildShiftGear();
public abstract void buildBreakSys();
public abstract void buildShell();
public abstract void buildFuelTank();
public abstract void buildSeat();
//返回产品对象
public Car getWholeCar(){
return car;
}
}
ConcreteBuilder(具体建造者):
public class ConcreteCarBuilder extends CarBuilder {
@Override
public void buildEngine() {
car.setEngine("高质量引擎");
}
@Override
public void buildWheel(){
car.setWheel("耐磨防滑轮胎");
}
@Override
public void buildAccelerator(){
car.setAccelerator("加速优秀油门");
}
@Override
public void buildClutch(){
car.setClutch("优质离合器");
}
@Override
public void buildShiftGear(){
car.setShiftGear("高精度变速箱");
}
@Override
public void buildBreakSys(){
car.setBreakSys("快速刹车系统");
}
@Override
public void buildShell(){
car.setbuildShell("高抗外壳");
}
@Override
public void buildFuelTank(){
car.setFuelTank("耐高温燃油箱");
}
@Override
public void buildSeat(){
car.setSeat("优质皮草座椅");
}
Director(指挥者):
public class CarAssembler{
private CarBuilder builder;
//装配工:负责汽车组装,扮演Director角色
public CarAssembler(CarBuilder builder){
this.builder = builder;
}
//产品构建组装方法
public Product construct(){
builder.buildEngine();
builder.buildWheel();
builder.buildAccelerator();
builder.buildClutch();
builder.buildShiftGear();
builder.buildBreakSys();
builder.buildShell();
builder.buildFuelTank();
builder.buildSeat();
//产品组装完成
return builder.getWholeCar();
}
}
四、讨论:指挥者类
指挥者类 Director 类十分重要,简单的 Director 类用于指导具体建造者如何构建产品,依次调用buildePartX() 方法,控制调用先后次序后返回完整对象。
1、省略 Director 类
为了简化系统结构,可将 Director 和 抽象建造者合并,提供逐步构建复杂产品对象的 construct() 方法。一般在抽象 Builder 类中,将该方法定义为静态 (static) 方法,便于直接调用。
传参的construct方法:
public abstract class CarBuilder{
protected static Car car = new Car();
public abstract void buildEngine();
public abstract void buildWheel();
public abstract void buildAccelerator();
public abstract void buildClutch();
public abstract void buildShiftGear();
public abstract void buildBreakSys();
public abstract void buildShell();
public abstract void buildFuelTank();
public abstract void buildSeat();
public static Car construct(CarBuilder builder){
builder.buildEngine();
builder.buildWheel();
builder.buildAccelerator();
builder.buildClutch();
builder.buildShiftGear();
builder.buildBreakSys();
builder.buildShell();
builder.buildFuelTank();
builder.buildSeat();
//产品组装完成
return car;
}
}
无参的construct方法:
public abstract class CarBuilder{
protected static Car car = new Car();
public abstract void buildEngine();
public abstract void buildWheel();
public abstract void buildAccelerator();
public abstract void buildClutch();
public abstract void buildShiftGear();
public abstract void buildBreakSys();
public abstract void buildShell();
public abstract void buildFuelTank();
public abstract void buildSeat();
public static Car construct(){
this.buildEngine();
this.buildWheel();
this.buildAccelerator();
this.buildClutch();
this.buildShiftGear();
this.buildBreakSys();
this.buildShell();
this.buildFuelTank();
this.buildSeat();
//产品组装完成
return car;
}
}
这里,construct() 方法定义了 buildPartX() 方法的调用次序,并为此提供了标准流程,类似于模板方法模式。
这种方式不影响可扩展性,简化了结构,但加重了建造者的职责,为更符合单一职责原则,大多数情况下并不推荐这样做。
2、引入钩子方法
建造者模式可以通过 Director 类更加精细地控制产品的创建过程,例如增加一类称为钩子方法(Hook Method) 的特殊方法来控制是否对某个buildPartX() 进行调用。
钩子方法的返回值为 boolean 类型,方法名一般为isXXX(),钩子方法定义在 抽象 Builder 类 中。
public abstract class CarBuilder{
protected static Car car = new Car();
public abstract void buildEngine();
public abstract void buildWheel();
public abstract void buildAccelerator();
public abstract void buildClutch();
public abstract void buildShiftGear();
public abstract void buildBreakSys();
public abstract void buildShell();
public abstract void buildFuelTank();
public abstract void buildSeat();
//钩子方法
public boolean isMotor(){ //是否为电动汽车
return false;
}
public Car createCar(){
return car;
}
}
public class ConcreteCarBuilder extends CarBuilder {
@Override
public void buildEngine() {
car.setEngine("高质量引擎");
}
@Override
public void buildWheel(){
car.setWheel("耐磨防滑轮胎");
}
@Override
public void buildAccelerator(){
car.setAccelerator("加速优秀油门");
}
@Override
public void buildClutch(){
car.setClutch("优质离合器");
}
@Override
public void buildShiftGear(){
car.setShiftGear("高精度变速箱");
}
@Override
public void buildBreakSys(){
car.setBreakSys("快速刹车系统");
}
@Override
public void buildShell(){
car.setbuildShell("高抗外壳");
}
@Override
public void buildFuelTank(){
car.setFuelTank("耐高温燃油箱");
}
@Override
public void buildSeat(){
car.setSeat("优质皮草座椅");
}
//覆盖钩子方法
@Override
public boolean isMotor(){ //是否为电动汽车
return true;
}
}
public class CarAssembler{
//产品构建组装方法:传入参数,更加灵活,根据是否重写钩子方法判断是否为电动汽车
public Product construct(CarBuilder builder){
builder.buildWheel();
builder.buildAccelerator();
builder.buildShiftGear();
builder.buildBreakSys();
builder.buildShell();
//通过钩子方法控制产品的构建
if(!builder.isMotor()){
builder.buildClutch(); //离合器
builder.buildEngine(); //引擎
builder.buildFuelTank(); //油箱
}
builder.buildSeat();
//产品组装完成
return builder.getWholeCar();
}
}
五、灵活建造者 : 链式建造
灵活的建造者模式被广泛地应用在 Spring框架
中,我们熟悉的StringBuilder
类也采用这一模式,灵活的建造者模式去除了指挥者类,使得用户可以参与到对象的构建过程中,但是要求用户本身对构建对象的方法有一定了解。
应用实例:
- jdk源码中,StringBuilder类(StringBuffer类)的核心方法为我们提供了链式创建对象的方法,并通过重写 toString() 方法 返回了一个完整的String对象。
- MyBatis中 SqlSessionFactoryBuiler 同样应用了链式建造方式创建对象。
实例代码:
Product(产品):
public class Car {
//定义部件,可以是值类型 / 引用类型
private String engine; //引擎
private String wheel; //轮胎
private String accelerator; //油门
private String clutch; //离合器
private String shiftGear; //变速器
private String breakSys; //刹车系统
private String shell; //外壳
private String fuelTank; //燃油箱
private String seat; //座椅
/*
* 省略所有属性的 Setter、Getter、toString 方法
*/
}
ConcreteBuilder(具体建造者):
public class CarBuilder {
//创建产品对象
protected Car car = new Car();
public CarBuilder buildEngine(String text) {
car.setEngine(text);
return this;
}
public CarBuilder buildWheel(String text) {
car.setWheel(text);
return this;
}
public CarBuilder buildAccelerator(String text) {
car.setAccelerator(text);
return this;
}
public CarBuilder buildClutch(String text) {
car.setClutch(text);
return this;
}
public CarBuilder buildShiftGear(String text) {
car.setShiftGear(text);
return this;
}
public CarBuilder buildBreakSys(String text) {
car.setBreakSys(text);
return this;
}
public CarBuilder buildShell(String text) {
car.setShell(text);
return this;
}
public CarBuilder buildFuelTank(String text) {
car.setFuelTank(text);
return this;
}
public CarBuilder buildSeat(String text) {
car.setSeat(text);
return this;
}
//返回产品对象
public Car build(){
return car;
}
}
测试代码:
Car car = new CarBuilder()
.buildAccelerator("加速优秀油门")
.buildBreakSys("快速刹车系统")
.buildClutch("优质离合器")
.buildEngine("高质量引擎")
.buildFuelTank("耐高温燃油箱")
.buildSeat("优质皮草座椅")
.buildShell("高抗外壳")
.buildShiftGear("高精度变速箱")
.buildWheel("耐磨防滑轮胎")
.build();
System.out.println(car);
六、特点
☯ 优点
- 建造者模式中,用户无需关心产品内部组成细节,将产品与本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。如有需要,可以将创建过程暴露给用户,使得对象的创建更加灵活,但这对用户提出了更高的要求。
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的建造者,用户使用不同的具体建造者就可得到不同的产对象。增加新的建造者无需修改原有类库代码,系统扩展方便,符合开闭原则。
- 可以更加精细的控制产品创建过程,创建思路更加清晰。
☯ 缺点
- 建造者模式创建产品具有较多共同点,其组成 成分相似,如若两对象组成部分相差过大,使用会受限。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统很庞大。