如何用建造者模式打造出独一无二的复杂对象
一、什么是建造者模式?
1.1 建造者模式的定义
将一个复杂对象的构造与它的表示分离,使同样的建造过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是一个负责的对象分解为多个简单的对象,然后一步步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
1.2 建造者模式的优点
- 封装性好,构建和表示分离。
- 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
- 客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
1.3 建造者模式的缺点
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。
注意:
建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。
二、 建造者模式的结构
建造者模式的结构包括以下几个角色:
- 产品(
Product
)角色:要创建的复杂对象。 - 抽象建造者(
Abstract Builder
)角色:定义创建产品各个部件的抽象接口。 - 具体建造者(
Concrete Builder
)角色:实现抽象建造者接口,构造和装配产品的各个部件。 - 导演(
Director
)角色:负责安排复杂对象的建造流程 ,指挥建造者按照特定的顺序构建产品。 - 客户(
Client
)角色:调用导演类来构建复杂对象。
三、建造者模式的实现
假设我们需要创建一个汽车对象,该汽车对象包含车身、轮胎、座椅等多个部件。我们可以使用建造者模式来构建这个复杂的汽车对象。
3.1 定义产品
首先,我们定义一个汽车类(Product)作为产品:
public class Car {private String body;private String tire;private String seat;public void setBody(String body) {this.body = body;}public void setTire(String tire) {this.tire = tire;}public void setSeat(String seat) {this.seat = seat;}public void show() {System.out.println("Car body: " + body);System.out.println("Car tire: " + tire);System.out.println("Car seat: " + seat);}
}
3.2 定义抽象建造者
然后,我们定义一个抽象的汽车建造者接口(Abstract Builder):
public abstract class CarBuilder {protected Car car;public Car getCar() {return car;}public void createCar() {car = new Car();}public abstract void buildBody();public abstract void buildTire();public abstract void buildSeat();
}
3.3 实现具体建造者类
接下来,我们实现两个具体的建造者类(Concrete Builder):
public class BMWCarBuilder extends CarBuilder{@Overridepublic void buildBody() {car.setBody("BMW Car Body");}@Overridepublic void buildTrie() {car.setTire("BMW Car Trie");}@Overridepublic void buildSeat() {car.setSeat("BMW Car Seat");}}public class BenzCarBuilder extends CarBuilder {@Overridepublic void buildBody() {car.setBody("Benz Car Body");}@Overridepublic void buildTrie() {car.setTire("Benz Car Trie");}@Overridepublic void buildSeat() {car.setSeat("Benz Car Seat");}
}
3.4 定义导演类
最后,我们定义一个导演类(Director)来协调建造者的工作:
public class CarDirector {private CarBuilder carBuilder;public void setCarBuilder(CarBuilder carBuilder) {this.carBuilder = carBuilder;}public Car constructCar() {carBuilder.createCar();carBuilder.buildBody();carBuilder.buildTire();carBuilder.buildSeat();return carBuilder.getCar();}
}
3.5 定义Client ,测试
在客户端(Client)中,我们可以如下使用建造者模式来创建汽车对象:
public class Client {public static void main(String[] args) {CarDirector director = new CarDirector();CarBuilder bmwBuilder = new BMWCarBuilder();director.setCarBuilder(bmwBuilder);Car bmwCar = director.constructCar();bmwCar.show();CarBuilder benzBuilder = new BenzCarBuilder();director.setCarBuilder(benzBuilder);Car benzCar = director.constructCar();benzCar.show();}
}
3.6 运行结果
四、建造者模式的应用场景
建造者模式的应用场景非常广泛,例如SpringBuilder
、Stream API
和Lombok
中的@Builder
注解等等;通常情况它使用于以下几个方面:
- 当创建复杂对象的算法应该独立于该对象的组成部分及其装配方式时,可以使用建造者模式。
- 当需要构建不同表示的产品(如不同类型的汽车)时,可以使用建造者模式。
- 当需要提供一个创建产品的接口,而具体的实现类则应该封装在内部时,可以使用建造者模式。
- 当构造过程必须允许创建不同表现形式的产品(如带参数或不带参数的构造)时,可以使用建造者模式。