🍀以下内容同步发布在我的个人博客https://www.lvjguo.top😊
建造者模式
1 介绍
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
特征:用户只需指定需要建造的类型就可以得到他们,建造的过程和细节不需要知道
类型:创建型
适用场景:
- 如果一个对象有非常复杂的内部结构(很多属性),想把复杂对象的创建和使用分离
- 需要生成的产品对象的属性相互依赖。建造模式可以强制实行一种分步骤进行的建造过程,因此,如果产品对象的一个属性必须在另一个属性被赋值之后才可以被赋值,使用建造模式是一个很好的设计思想。
优点:
- 封装性好,创建和使用分离,客户端不必知道产品内部的组成细节
- 扩展性好、建造类之间是相互独立的
- 由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他模块产生任何影响
缺点:
建造者模式会产生多余的Builder对象,并且如果产品内部发生改变,建造者都要修改,成本较大
模式组成:
通过上面的UML类图可以看出,建造者模式分为以下4个角色
组成(角色) | 作用 |
---|---|
抽象建造者(Builder) | 为创建一个产品对象的各个部件指定抽象接口 |
具体建造者(ConcreteBuilder) | 实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口 |
指导者(Director) | 调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建 |
产品类(Product) | 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。 |
2 示例
我们考虑一下一辆汽车的生产。生产汽车是一个复杂的过程,它包含轮胎的安装、引擎的装配、底盘与车身的生产等。客户把汽车设计图纸告诉项目经理,项目经理指挥装配工人进行生产以及安装,最后完成整个汽车的生产,所以本实例用建造者模式实现比较适合。
这里汽车是产品,包括轮胎、发动机、底盘和车身等组成部分。具体装配工人是具体建造者,他们负责生产汽车所需的零件。项目经理是指挥者,他负责指挥装配工人进行装配。
- 具体的产品对象
@Data
public class Car {
private String engine; //发动机
private String tyre; //轮胎
private String chassis; //底盘
private String body; //车身
}
- 抽象建造者,创建一个Product对象的各个部件指定的抽象接口
public abstract class CarBuilder {
public abstract void buildEngine(String engine);
public abstract void buildTyre(String tyre);
public abstract void buildChassis(String chassis);
public abstract void buildBody(String body);
public abstract Car makeCar();
}
- 具体建造者,构件和装配各个部件
public class CarActualBuilder extends CarBuilder {
private Car car = new Car();
@Override
public void buildEngine(String engine) {
car.setEngine(engine);
}
@Override
public void buildTyre(String tyre) {
car.setTyre(tyre);
}
@Override
public void buildChassis(String chassis) {
car.setChassis(chassis);
}
@Override
public void buildBody(String body) {
car.setBody(body);
}
@Override
public Car makeCar() {
return car;
}
}
- 指导者,构建一个使用Builder接口的对象,来创建一个复杂的对象,它可以隔离客户与对象的生产过程,并且负责控制产品对象的生产过程。
public class Manager {
private CarBuilder carBuilder;
public void setCarBuilder(CarBuilder carBuilder) {
this.carBuilder = carBuilder;
}
public Car makeCourse(String engine, String tyre,String chassis, String body){
this.carBuilder.buildEngine(engine);
this.carBuilder.buildTyre(tyre);
this.carBuilder.buildChassis(chassis);
this.carBuilder.buildBody(body);
return this.carBuilder.makeCar();
}
}
- 客户端
public class Test {
public static void main(String[] args) {
CarBuilder carBuilder = new CarActualBuilder();
Manager manager = new Manager();
manager.setCarBuilder(carBuilder);
Car car = manager.makeCourse("装配发动机",
"安装轮胎",
"安装底盘",
"安装车身");
System.out.println(car);
}
}
//控制台输出:
//Car(engine=装配发动机, tyre=安装轮胎, chassis=安装底盘, body=安装车身)
3 扩展
上述案例我们只有一个产品(汽车),所以我们完全可以简化建造者模式,由于产品种类固定一种,那么就无需提供抽象建造者接口,直接提供一个具体的建造者就行,其次,对于创建一个复杂的对象,可能会有很多种不同的选择和步骤,我们可以省略“指导者”角色,让Builder自己扮演指导者和建造者双重角色。也就是说,用客户端来联系建造者类去构建需要的复杂对象。
- 将产品和建造者合并在一起
@Data
public class Car {
private String engine; //发动机
private String tyre; //轮胎
private String chassis; //底盘
private String body; //车身
public Car(CarBuilder carBuilder) {
this.engine = carBuilder.engine;
this.tyre = carBuilder.tyre;
this.chassis = carBuilder.chassis;
this.body = carBuilder.body;
}
/**
*建造者
*/
public static class CarBuilder {
private String engine; //这里可以设置默认值
private String tyre;
private String chassis;
private String body;
public CarBuilder buildEngine(String engine){
this.engine = engine;
return this;
}
public CarBuilder buildTyre(String tyre) {
this.tyre = tyre;
return this;
}
public CarBuilder buildChassis(String chassis) {
this.chassis = chassis;
return this;
}
public CarBuilder buildBody(String body) {
this.body = body;
return this;
}
public Car build(){
return new Car(this);
}
}
}
- 客户端不依赖指导者,直接通过产品中的建造器创建产品实例
public class Test {
public static void main(String[] args) {
Car car = new Car.CarBuilder().buildEngine("装配发动机")
.buildTyre("安装轮胎")
.buildChassis("安装底盘")
.buildBody("安装车身").build();
System.out.println(car);
}
}
4 与工厂模式的区别
建造者模式中是由客户端联系指导者,指导者管理建造者得到最终的产品。即建造者模式可以强制实行一种分步骤进行的构造过程。
工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品。而在建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给指导者,由指导者负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。