一、什么是建造者模式
建造者模式是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式属于创建型模式,对使用者而言,只需要指定需要建造的类型就可以获得对象,建造过程和细节不需要了解。在实际的开发过程中,使用 Builder Pattern 来替代多参数构造函数是一个比较好的实践法则。
建造者模式的概念听上去有点抽象,但是实际上可以这么说,基本上大家都用过,只是可能自己不知道这就是建造者模式而已。
二、建造者模式角色
1️⃣产品(Product):要创建的产品对象。
public class Product {
private String name;
private Integer val;
Product(String name, Integer val) {
this.name = name;
this.val = val;
}
@Override
public String toString() {
return "Product is " + name + " value is " + val;
}
}
2️⃣抽象建造者(Builder):建造者的抽象类,规范产品对象的各个组成部分的建造,一般由子类实现具体建造过程。
public abstract class Builder {
protected Integer val;
protected String name;
// 设置产品不同部分,以获得不同的产品
public abstract void setVal(Integer val);
// 设置名字 公用方法
public void setName(String name) {
this.name = name;
}
// 建造产品
public abstract Product buildProduct();
}
3️⃣具体建造者(ConcreteBuilder):具体的 Builder 类,根据不同的业务逻辑,具体到各个对象的各个组成部分的建造。
public class ConcreteBuilder extends Builder {
@Override
public void setVal(Integer val) {
this.val = val + 100;
}
@Override
// 组建一个产品
public Product buildProduct() {
// 此处还可以写特殊的校验逻辑
return new Product(name, val);
}
}
4️⃣调用者(Director):调用具体的建造者来创建各个对象的各个部分。
public class Director {
private Builder builder = new ConcreteBuilder();
public Product getAProduct() {
// 设置不同的零件,产生不同的产品
builder.setName("ProductA");
builder.setVal(2);
return builder.buildProduct();
}
}
三、示例
在设计模式中对 Builder Pattern 的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成。在实际的开发过程中,使用 Builder Pattern 来替代多参数构造函数是一个比较好的实践法则。
常常遇到编写一个这样的实现类,这个类拥有多个构造函数:
DoContact(String name);
DoContact(String name, int age);
DoContact(String name, int age, String address);
DoContact(String name, int age, String address, int cardID);
这样一系列的构造函数主要目的就是为了提供给客户更多的调用选择,以处理不同的构造请求。这种方法很常见,很有效力,但缺点也很多:
1️⃣类的作者不得不书写多种参数组合的构造函数,而且其中还需要设置默认参数值,这是一个细心而又枯燥的工作。
2️⃣其次,这样的构造函数灵活性也不高,而且在调用时不得不提供一些没有意义的参数值,例如,DoDoContact("Ace", -1, "SH"),显然年龄为负数没有意义,但是又不得不这样做,以符合 Java 的规范。如果这样的代码发布后,后面的维护者就会很头痛,因为根本不知道这个 -1 是什么含义。
对于这样的情况,就非常适合使用 Builder Pattern。Builder Pattern的要点就是通过一个代理来完成对象的构建过程。
这个代理职责就是完成构建的各个步骤,同时它也是易扩展的。下面是改写自 Effective Java 里面的一段代码:
public class DoContact {
private final int age;
private final int safeID;
private final String name;
private final String address;
public int getAge() {
return age;
}
public int getSafeID() {
return safeID;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public static class Builder {
private int age = 0;
private int safeID = 0;
private String name = null;
private String address = null;
// 构建的步骤
public Builder(String name) {
this.name = name;
}
public Builder age(int val) {
this.age = val;
return this;
}
public Builder safeID(int val) {
this.safeID = val;
return this;
}
public Builder address(String val) {
this.address = val;
return this;
}
// 构建,返回一个新对象
public DoContact build() {
return new DoContact(this);
}
}
private DoContact(Builder b) {
age = b.age;
safeID = b.safeID;
name = b.name;
address = b.address;
}
}
最终,调用者可以很灵活的去构建这个对象:
public class kfd {
public static void main(String[] args) {
DoContact object = new DoContact.Builder("MChopin").age(18)
.address("shanghai").build();
System.out.println("name=" + object.getName() + " age=" + object.getAge()
+ " address=" + object.getAddress());
}
}
四、建造者模式优缺点
1️⃣优点
- 封装性好,创建和使用分离
- 扩展性好,建造类之间独立,一定程度上实现了解耦
2️⃣缺点
- 产生多余的 Builder 对象
- 产品内部发生变化时,建造者都需要修改,成本较大
五、建造者模式和工厂模式区别
建造者模式优点类似于工厂模式,都是用来创建一个对象,但是有很大的区别,主要区别如下:
1️⃣建造者模式更加注重方法的调用顺序,工厂模式注重于创建完整对象。
2️⃣建造者模式根据不同的产品零件和顺序可以创造出不同的产品,而工厂模式创建出来的产品都是一样的。
3️⃣建造者模式使用者需要知道这个产品有哪些零件组成,而工厂模式的使用者不需要知道,直接创建就行。