建造者模式

模式动机

在现实世界以及软件系统中,存在一些复杂对象,它们拥有多个组成部分,比如汽车包括车轮、方向盘、发动机等,但对于大部分用户来说,他们并不关心这些组装细节,也不会使用单独的配件,而是直接去用完整的汽车。这就引入了建造者模式该模式可以将部件和其组装过程分开,一步一步创建一个复杂对象。用户只要制定对象的类型就可以得到对象,无需知道内部构造细节。

现在着眼于软件开发,一个复杂系统可能包含许多成员属性,这些成员属性可能引用了某个对象,在赋值的时候可能存在这样那样的限制条件。我们要做的就是通过一个建造者来封装这些复杂的“赋值”组合过程,返回给客户端一个已经建造完毕的完整产品对象,而用户无需关心该对象所包含的属性和它们的组装方式。即分离构建与表示,同样的构建过程可以获得不同的表示

应用

一步一步创建复杂对象,用户只需要告知复杂对象的类型和内容就可以构建他们。

建造者模式包含如下角色:

  • 抽象建造者Builder
  • 具体建造者ConcreteBuilder
  • 指挥者Director
  • 产品Product

建造者模式还引入了一个关键类“指挥者”Director,它有两个作用:

  1. 隔离客户端和生产过程
  2. 控制产品的生产,也就是利用Builder来build产品

具体实现上,指挥者面向抽象建造者编程,客户端只需要告知指挥者具体建造者的类型,指挥者就可以调用建造者的相关方法构建一个完整产品并返回。

典型代码如下:

public class Product {
private String partA; //可以是任意类型
private String partB;
private String partC;
//partA的Getter方法和Setter方法省略
//partB的Getter方法和Setter方法省略
//partC的Getter方法和Setter方法省略
}

public abstract class Builder {
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public Product getResult() {
return product;
}
}

public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void setBuilder(Builder builder) {
// 客户端在这里告知指挥者具体的建造者是哪一个
// 所以实际上客户端和Director与Builder之间都有耦合
this.builder = builer;
}
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}

客户端代码片段如下:

// ...
Builder builder = new ConcreteBuilder(); // 客户端获取具体建造者类型
Director director = new Director(builder); // 客户端通知指挥者具体建造者
Product product = director.construct(); // 客户端通过指挥者直接获取完整产品
// ...

实例:KFC套餐

KFCWaiter即充当指挥者的角色

优点

  1. 客户端不必知道产品内部组成的细节,产品本身与创建过程解耦,相同的创建过程可以创建不同的产品(根据建造者实例的不同)
  2. 更精细的控制产品创建过程
  3. 增加新的建造者时无需修改原有具体类的代码,指挥者类是面向接口(抽象建造者类)编程的,符合开闭原则

缺点

  1. 使用范围受限,当产品之间差异太大时,不适合建造者模式
  2. 如果产品内部变化复杂,需要定义很多具体建造者类来实现这种变化,系统可能会很庞大

适用场合

  1. 需要生成的产品对象有复杂的内部结构
  2. 需要生成的产品对象的属性互相依赖,并且需要制定生成顺序
  3. 对象的创建过程独立于创建该对象的类:即引入了指挥者来从全局上负责产品的创建,而不是建造者来创建完整的产品
  4. 隔离复杂对象的创建和使用,使得相同的创建过程可以创建不同的产品

实例:游戏地图、人物

在许多游戏中,地图包括多种元素,比如天空、地面、背景、装饰物等等,人物则包括身体、服装、装备等组成部分,可以使用建造者模式对他们进行设计,通过不同的具体建造者创建出不同的地图和人物。

简化建造者模式

省略抽象建造者

当系统确定只需要一个具体建造者的时候,可以忽略抽象建造者,因为没有扩展的必要

省略指挥者

在上述条件下,如果抽象建造者已被省略,那么指挥者也可以被省略,让唯一的一个具体建造者同时扮演指挥者和建造者的角色。

对比抽象工厂模式

  1. 建造者模式返回的是一个组装好的产品,而抽象工厂返回的是一系列处于同一产品族中的产品。
  2. 抽象工厂模式中,客户端实例化具体工厂,调用其方法来获取所需对象;建造者模式中,客户端可以不调用建造者的方法,而是通过指挥者来指导生成对象,侧重于一步步构建复杂对象,返回一个完整产品对象
Director director = new Director();
director.setBuilder(new RedBuilder());
director.buildCap();
director.setBuilder(new GreenBuilder());
director.buildClothes();
director.setBuilder(new BlackBuilder());
director.setShoes();
director.getRole();
  1. 通俗的讲,抽象工厂模式就是一个汽车配件生产工厂,而建造者模式是一个汽车组装工厂,通过这些配件可以创建一辆完整的汽车。

(•‿•)