目录
一、什么是建造者模式
二、建造者模式的应用场景
三、建造者模式的优缺点
3.1. 优点
3.2. 缺点
四、建造者模式示例
4.1. 问题描述
4.2. 问题分析
4.3. 代码实现
五、建造者模式的另一种实现方式
六、总结
一、什么是建造者模式
建造者模式(Builder Pattern)是一种创建型设计模式(Creational Pattern),可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。它提供了一种更加灵活和可扩展的方式来创建对象,同时也避免了构造函数参数过多导致的代码可读性和维护性问题。
建造者模式主要包含以下四类角色:
- 产品(Product):表示被构建的复杂对象。通常包含多个部分,具体部分的创建由具体建造者负责。
- 抽象建造者(Builder):定义了创建产品各个部分的抽象接口,以及返回产品的方法。
- 具体建造者(Concrete Builder):实现了抽象建造者接口,负责具体部分的创建,并返回一个组装好的产品。
- 指挥者(Director):调用具体建造者来创建产品对象,并控制构建过程的顺序。
二、建造者模式的应用场景
建造者模式创建的是复杂对象,其产品的各个部分经常面临较大变化,但将它们组合在一起的算法却相对稳定,所以它适用于以下情况:
- 当对象的构建过程较为复杂,包含多个步骤或者需要按照一定顺序构建时。
- 当需要创建的对象具有多个表示,但构建过程相同时,可以使用建造者模式。
- 当需要创建的对象具有复杂的内部结构,且需要按照一定的步骤进行构造时,可以使用建造者模式。
三、建造者模式的优缺点
3.1. 优点
- 封装性:建造者模式将对象的构建过程和表示过程分离,客户端只需要知道产品的类型以及包含哪些部分,而不需要知道内部的具体构建细节。这样可以更好地封装对象,提高代码的可读性和可维护性。
- 可扩展性:建造者模式允许在不修改已有代码的情况下扩展新的产品部件,只需要增加新的具体建造者类即可。这样可以提高系统的可扩展性,降低维护成本。
- 清晰性:通过将构建过程分解为多个步骤,使得构建过程更加清晰,便于维护和理解。
- 灵活性:客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响。
3.2. 缺点
- 产品的组成部分必须相同:建造者模式要求所有产品都具有相同的组成部分,这在一定程度上限制了其使用范围。如果某些产品需要特殊的构建过程或者组成部分不同,那么这种模式可能就不适用。
- 产品内部变化复杂时维护成本较高:如果产品的内部变化复杂,那么当产品内部发生变化时,所有的Builder类都需要同步修改,这可能会导致维护成本较高。
四、建造者模式示例
4.1. 问题描述
假设我们要制造一辆汽车,汽车由车身、引擎、轮胎等部件组成。汽车的不同部件都有不同的规格可供选择,如何通过代码来实现汽车的构建过程。
4.2. 问题分析
问题的目的是要通过代码来创建汽车的实例对象,汽车的组成都是由车身、引擎等部件构成,只是不同部件有不同的表示(规格),这就符合了建造者模式的使用场景。问题当中的汽车(Car)显然就是我们建造者模式中的产品(Product),汽车中需要有多个部件:车身(body)、引擎(engine)、轮胎(tire),为了统一创建汽车的功能接口,我们定义其抽象建造者(Builder)为汽车建造者(CarBuilder),最后定义一个汽车建造指挥者(CarDirector)用来协调建造过程,当我们有了一个新的产品时,就可以通过新增一个汽车创建者的实现类来完成新产品的组成定义,比如有一个汽车产品A,其车身为碳纤维(carbon fibre)的,引擎是电动的(electric),轮胎是充气橡胶的(inflatable rubber),那么我们就可以新增一个A款汽车的建造者(CarABuilder)来实现这款汽车对象的创建。
4.3. 代码实现
经过上一步的分析之后,下面我们通过代码来实现它:
/*** 定义汽车类*/
class Car{private String body;private String engine;private String tire;
public String getBody() {return body;}
public void setBody(String body) {this.body = body;}
public String getEngine() {return engine;}
public void setEngine(String engine) {this.engine = engine;}
public String getTire() {return tire;}
public void setTire(String tire) {this.tire = tire;}
}
/*** 汽车创建者接口*/
interface CarBuilder{void buildBody();void buildEngine();void buildTire();Car getCar();
}
/*** 汽车创建指挥者*/
class CarDirector{private final CarBuilder carBuilder;public CarDirector(CarBuilder carBuilder){this.carBuilder = carBuilder;}public Car construct(){carBuilder.buildBody();carBuilder.buildEngine();carBuilder.buildTire();return carBuilder.getCar();}
}
/*** A型号汽车创建者*/
class CarABuilder implements CarBuilder{private final Car car = new Car();@Overridepublic void buildBody() {car.setBody("carbon fibre");}@Overridepublic void buildEngine() {car.setEngine("electric");}@Overridepublic void buildTire() {car.setTire("inflatable rubber");}@Overridepublic Car getCar() {return car;}
}
当我们需要创建一个A型号的汽车的对象时,我们只需要这样做就可以了:
Car carA = new CarDirector(new CarABuilder()).construct();
五、建造者模式的另一种实现方式
当一个对象的属性过多时,通过常规的实例化方法实现的代码的可读性会非常差,并且还需要使用者对内部的所有属性都有一定的了解,此时我们可以通过给这个类专门写一个内部类作为建造者的方式将一些创建逻辑或者约束条件封装到建造者内部,使使用者可以较为简单地创建复杂对象。
我们以java.util包下的抽象类Calendar为例,打开Calendar类,我们可以发现里面有大量的属性:
并且作为抽象类,Calendar类还会有不同的实现:
如果没有建造者的话,在创建一个Calendar的对象的时候无疑是很头疼的。所以Calendar类内部为我们提供了一个建造者:
通过这个建造者我们就可以很轻松地创建一个Calendar类的实例了:
Calendar.Builder builder = new Calendar.Builder();
builder.setCalendarType("iso8601");
builder.setDate(2024, 3, 6);
Calendar calendar = builder.build();
System.out.println(calendar.getTime());
六、总结
建造者模式是一种非常有用的设计模式,它可以帮助我们更好地组织复杂对象的构建过程,提高代码的可读性和可维护性。通过将构建过程与表示分离,建造者模式使得对象的创建变得更加灵活和可控。在实际项目中,我们可以根据具体需求来选择是否使用建造者模式,以提高代码的质量和可扩展性。
希望通过本文的介绍,您对建造者模式有了更深入的理解,能够在实际项目中灵活运用。谢谢阅读!