目录
1.概述
建造者模式 (Builder Pattern) 是一种创建型设计模式,用于创建复杂对象。它将对象的构建过程分离成独立的部分,同时允许按照不同的方式构建对象。通常情况下,当一个对象的构建过程有多个步骤,且这些步骤可以按照不同的顺序来构建时,建造者模式就非常有用。通过将构建逻辑封装到具体的建造者类中,客户端可以使用相同的构建过程来创建不同类型的对象。
2.结构
建造者模式包含如下角色:
- 抽象建造者类 (Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。
- 具体建造者类 (ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。
- 产品类 (Product):要创建的复杂对象。
- 指挥者类 (Director) :调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。类图如下:
3.实例
【例】创建共享单车:生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。这里 Bike 是产品,包含车架,车座等组件;Builder 是抽象建造者,MobikeBuilder 和 OfoBuilder 是具体的建造者;Director 是指挥者。类图如下:
具体代码如下:
3.1.产品类
Bike.java
java
public class Bike {
private String frame;//车架
private String seat;//车座
public String getFrame() {
return frame;
}
public void setFrame(String frame) {
this.frame = frame;
}
public String getSeat() {
return seat;
}
public void setSeat(String seat) {
this.seat = seat;
}
}
3.2.抽象建造者类
Builder.java
java
public abstract class Builder {
//声明Bike类型的变量,并进行赋值
protected Bike bike = new Bike();
public abstract void buildFrame();
public abstract void buildSeat();
//构建自行车的方法
public abstract Bike createBike();
}
3.3.具体建造者类
MobileBuilder.java
java
//具体的构建者,用来构建摩拜单车对象
public class MobileBuilder extends Builder{
public void buildFrame() {
bike.setFrame("碳纤维车架");
}
public void buildSeat() {
bike.setSeat("真皮车座");
}
public Bike createBike() {
return bike;
}
}
OfoBuilder.java
java
public class OfoBuilder extends Builder{
public void buildFrame() {
bike.setFrame("铝合金车架");
}
public void buildSeat() {
bike.setSeat("橡胶车座");
}
public Bike createBike() {
return bike;
}
}
3.4.指挥者类
Director.java
java
public class Director {
//声明 builder 类型的变量
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
//组装自行车的功能
public Bike construct() {
builder.buildFrame();
builder.buildSeat();
return builder.createBike();
}
}
3.5.测试
Client.java
java
public class Client {
public static void main(String[] args) {
//创建指挥者对象
Director director = new Director(new MobileBuilder());
//让指挥者只会组装自行车
Bike bike = director.construct();
System.out.println(bike.getFrame());
System.out.println(bike.getSeat());
}
}
注意:上面示例是 Builder 模式的常规用法,指挥者类 Director 在建造者模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把指挥者类和抽象建造者进行结合。
java
// 抽象 builder 类
public abstract class Builder {
protected Bike mBike = new Bike();
public abstract void buildFrame();
public abstract void buildSeat();
public abstract Bike createBike();
public Bike construct() {
this.buildFrame();
this.BuildSeat();
return this.createBike();
}
}
4.优缺点
(1)建造者模式具有以下几个优点:
- 分离构建过程和表示:建造者模式可以将一个复杂对象的构建过程与它的表示分离,使得相同的构建过程可以创建不同的表示。这样可以使代码结构更清晰,易于阅读和维护。
- 隐藏产品内部细节:建造者模式将对象的构建过程封装在具体的建造者类中,使得客户端可以不需要知道产品的内部实现细节,只需要关注如何组装和使用产品。
- 提供更好的控制:由于建造者模式将构建过程分步进行,可以通过指定不同的具体建造者,实现不同的构建过程。这样就可以更灵活地控制构建过程,根据需要定制复杂对象的创建方式。
(2)建造者模式的一些缺点包括:
- 增加了代码量:引入建造者模式会增加额外的代码量,因为需要定义抽象建造者和具体建造者类,以及指挥者类等。对于简单的对象构建过程,可能会显得繁琐。
- 对客户端的要求高:客户端需要显式地创建指挥者对象,并指定具体的建造者,且需要了解建造者类的接口和使用方法。这对于不熟悉建造者模式的开发人员来说可能会增加学习成本。
综上所述,建造者模式在创建复杂对象时具有很多优点,但也需要在实际应用中权衡其优缺点来决定是否使用。
5.使用场景
(1)建造者模式适用于以下几种场景:
- 当对象的构建过程比较复杂,需要有多个步骤或者按照不同的顺序构建时,可以使用建造者模式。例如,创建一个包含多个部分的电子产品,每个部分的构建方式可能不同,而且可以按照不同的顺序组装。
- 当需要创建的对象有多个不同的表示或配置时,可以使用建造者模式。使用不同的具体建造者可以创建不同的对象表示,而且可以在运行时动态地选择具体建造者。
- 当想要隔离产品的构造和表示细节,使得构造过程和最终的产品解耦时,可以使用建造者模式。客户端只需要关注构建过程和产品的使用,而不需要关注产品的内部实现细节。
- 当需要创建一系列相似但稍有差异的对象时,可以使用建造者模式。通过复用相同的构建逻辑和变化的部分,可以高效地创建多个对象。
- 当需要在一个对象的构建过程中能够灵活地修改构建方式或者增加更多的构建步骤时,可以使用建造者模式。具体建造者的实现可以根据需求进行扩展和修改,而不会影响到客户端代码。
(2)需要注意的是,如果对象的构建过程相对简单,没有多个步骤或者差异很小,或者只有少数几个属性需要设置,那么使用建造者模式可能会显得过于繁琐,可以考虑使用其他创建型模式或者简化构建过程。
6.模式扩展
建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构 。
(1)重构前代码如下:
Phone.java
java
public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Phone(String cpu, String screen, String memory, String mainboard) {
this.cpu = cpu;
this.screen = screen;
this.memory = memory;
this.mainboard = mainboard;
}
@Override
public String toString() {
return "Phone{" +
"cpu='" + cpu + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainboard='" + mainboard + '\'' +
'}';
}
}
Client.java
java
public class Client {
public static void main(String[] args) {
//构建Phone对象
Phone phone = new Phone("麒麟","三星屏幕","金士顿","华硕主板");
System.out.println(phone);
}
}
上面在客户端代码中构建Phone对象,传递了四个参数,如果参数更多,那么代码的可读性会变差,以及使用的成本会变高。
(2)重构后代码如下:
Phone.java
java
public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainboard;
private Phone(Builder builder) {
cpu = builder.cpu;
screen = builder.screen;
memory = builder.memory;
mainboard = builder.mainboard;
}
public static final class Builder{
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Builder(){}
public Builder cpu(String val){
cpu = val;
return this;
}
public Builder screen(String val){
screen = val;
return this;
}
public Builder memory(String val){
memory = val;
return this;
}
public Builder mainboard(String val){
mainboard = val;
return this;
}
public Phone build(){
return new Phone(this);
}
}
@Override
public String toString() {
return "Phone{" +
"cpu='" + cpu + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainboard='" + mainboard + '\'' +
'}';
}
}
Client.java
java
public class Client {
public static void main(String[] args) {
//构建Phone对象
Phone phone = new Phone.Builder()
.cpu("麒麟")
.memory("金士顿")
.screen("三星屏幕")
.mainboard("华硕")
.build();
System.out.println(phone);
}
}
重构后的代码在使用起来更方便,某种程度上也可以提高开发效率。从软件设计上,对程序员的要求比较高。
7.创建者模式对比
(1)工厂方法模式 VS 建造者模式
工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。
(2)抽象工厂模式 VS 建造者模式
- 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可。
- 建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。