建造者模式 (Builder Pattern) 是一种创建型设计模式,用于创建复杂对象。它将对象的构建过程分离成独立的部分,同时允许按照不同的方式构建对象。通常情况下,当一个对象的构建过程有多个步骤,且这些步骤可以按照不同的顺序来构建时,建造者模式就非常有用。通过将构建逻辑封装到具体的建造者类中,客户端可以使用相同的构建过程来创建不同类型的对象。
建造者模式包含如下角色:
【例】创建共享单车:生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。这里 Bike 是产品,包含车架,车座等组件;Builder 是抽象建造者,MobikeBuilder 和 OfoBuilder 是具体的建造者;Director 是指挥者。类图如下:
具体代码如下:
Bike.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;
}
}
Builder.java
public abstract class Builder {
//声明Bike类型的变量,并进行赋值
protected Bike bike = new Bike();
public abstract void buildFrame();
public abstract void buildSeat();
//构建自行车的方法
public abstract Bike createBike();
}
MobileBuilder.java
//具体的构建者,用来构建摩拜单车对象
public class MobileBuilder extends Builder{
public void buildFrame() {
bike.setFrame("碳纤维车架");
}
public void buildSeat() {
bike.setSeat("真皮车座");
}
public Bike createBike() {
return bike;
}
}
OfoBuilder.java
public class OfoBuilder extends Builder{
public void buildFrame() {
bike.setFrame("铝合金车架");
}
public void buildSeat() {
bike.setSeat("橡胶车座");
}
public Bike createBike() {
return bike;
}
}
Director.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();
}
}
Client.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 在建造者模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把指挥者类和抽象建造者进行结合。
// 抽象 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();
}
}
(1)建造者模式具有以下几个优点:
(2)建造者模式的一些缺点包括:
综上所述,建造者模式在创建复杂对象时具有很多优点,但也需要在实际应用中权衡其优缺点来决定是否使用。
(1)建造者模式适用于以下几种场景:
(2)需要注意的是,如果对象的构建过程相对简单,没有多个步骤或者差异很小,或者只有少数几个属性需要设置,那么使用建造者模式可能会显得过于繁琐,可以考虑使用其他创建型模式或者简化构建过程。
建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。
(1)重构前代码如下:
Phone.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
public class Client {
public static void main(String[] args) {
//构建Phone对象
Phone phone = new Phone("麒麟","三星屏幕","金士顿","华硕主板");
System.out.println(phone);
}
}
上面在客户端代码中构建Phone对象,传递了四个参数,如果参数更多,那么代码的可读性会变差,以及使用的成本会变高。
(2)重构后代码如下:
Phone.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
public class Client {
public static void main(String[] args) {
//构建Phone对象
Phone phone = new Phone.Builder()
.cpu("麒麟")
.memory("金士顿")
.screen("三星屏幕")
.mainboard("华硕")
.build();
System.out.println(phone);
}
}
重构后的代码在使用起来更方便,某种程度上也可以提高开发效率。从软件设计上,对程序员的要求比较高。
(1)工厂方法模式 VS 建造者模式
工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。
(2)抽象工厂模式 VS 建造者模式