建造者模式
- 建造者模式属于创建型模式(即帮使用者创建对象),它提供了一种创建对象的最佳方式
- 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示<>
- 主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象
- 用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象 <===> 把内部的建造过程和细节隐藏起来
- 例子:
- 工厂(建造者模式):负责制造汽车(组装过程和细节在工厂内)
- 汽车购买者(用户):你只需要说出你需要的型号(对象的类型和内容),然后直接购买就可以使用了(不需要知道汽车时怎么组装的)
- 可以通过工厂模式制造零件,然后使用建造者模式组装在一起,构建一个复杂对象,然后再去使用
角色分析
- 建造者模式的四个角色
- Product(产品角色): 一个具体的产品对象。
- Builder(抽象建造者): 创建一个Product对象的各个部件指定的 接口/抽象类。
- ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
- Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个
复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:
负责控制产品对象的生产过程。

- 在做房子的时候,可以将做房子概述为以下的步骤:打地基 => 建楼 => 装修 => 验收
- 如果要做一个房子,首先要找到一个建筑公司(
Director
)进行设计,画图纸(抽象的Builder
),然后找工人(具体的Builder
)根据图纸进行建设,最后做好一个房子(Product
) - 那么可以根据这一个构建过程,建造出不同的房子,可以是高楼大厦,也可以是小别墅小洋房,这就是同样的构建过程可以创建不同的表示
有指挥者 - 由指挥者规定构建过程
public class Product {
private String buildA;
private String buildB;
private String buildC;
private String buildD;
public String getBuildA() { return buildA; }
public void setBuildA(String buildA) { this.buildA = buildA; }
public String getBuildB() { return buildB; }
public void setBuildB(String buildB) { this.buildB = buildB; }
public String getBuildC() { return buildC; }
public void setBuildC(String buildC) { this.buildC = buildC; }
public String getBuildD() { return buildD; }
public void setBuildD(String buildD) { this.buildD = buildD; }
@Override
public String toString() {
return "Product{" +
"buildA='" + buildA + '\'' +
", buildB='" + buildB + '\'' +
", buildC='" + buildC + '\'' +
", buildD='" + buildD + '\'' +
'}';
}
}
----------------------------------------------------------------------
public abstract class Builder {
abstract void buildA();
abstract void buildB();
abstract void buildC();
abstract void buildD();
abstract Product getProduct();
}
----------------------------------------------------------------------
public class Worker extends Builder {
private Product product;
public Worker() {
product = new Product();
}
@Override
void buildA() {
product.setBuildA("打地基");
System.out.println("打地基");
}
@Override
void buildB() {
product.setBuildB("建楼");
System.out.println("建楼");
}
@Override
void buildC() {
product.setBuildC("装修");
System.out.println("装修");
}
@Override
void buildD() {
product.setBuildD("装家具");
System.out.println("装家具");
}
@Override
Product getProduct() {
return product;
}
}
----------------------------------------------------------------------
public class Director {
public Product builder(Builder builder){
builder.buildA();
builder.buildB();
builder.buildC();
builder.buildD();
return builder.getProduct();
}
}
----------------------------------------------------------------------
public class Test {
public static void main(String[] args) {
Director director = new Director();
Product product = director.builder(new Worker());
System.out.println(product.toString());
}
}
- 那么当我们想切换构建顺序的时候,只需要操作指挥者就好了,这样就只需要将工人聚成一个类,这个类怎么构建生成,由指挥者来完成
- 同样的构建过程可以创建不同的表示 ==> 就是假设有不同的工人,就可以建造不同的房子
- 这是建造者模式的常规用法,Director在建造者模式中具有很重要的作用,它用于指导具体的构建者如何构建产品,控制调用的先后次序,并向调用者返回完整的产品类
- 但是有些情况下需要简化系统结构,可以把Director和抽象建造者模式结合,可以通过静态内部类方式实现零件无序装配构造,这种方式使用更加灵活,更符合定义
- 内部有复杂对象的默认实现,使用时可以根据用户需求自由定义更改内容,并且无需改变具体的构造方式就可以生产出不同的复杂产品
- 比如在点餐时,点单员(具体构建者)可以随意搭配任意几种产品(零件)组成一款套餐(产品)
- 这样就比第一种方式少了指挥者,而且因为第二种方式把指挥者交给用户来操作,使得产品的创建更加简单灵活
没有指挥者 - 若不配置则按默认构建过程生产
public class Product {
private String A = "乌龙茶";
private String B = "鸡蛋肠";
private String C = "虾饺";
private String D = "小笼包";
public String getA() { return A; }
public void setA(String A) { this.A= A; }
public String getB() { return B; }
public void setB(String B) { this.B = B; }
public String getC() { return C; }
public void setC(String C) { this.C = C; }
public String getD() { return D; }
public void setD(String D) { this.D = D; }
@Override
public String toString() {
return "Product{" +
"A='" + A + '\'' +
", B='" + B + '\'' +
", C='" + C + '\'' +
", D='" + D + '\'' +
'}';
}
}
----------------------------------------------------------------------
public abstract class Builder {
abstract Builder buildA(String msg);
abstract Builder buildB(String msg);
abstract Builder buildC(String msg);
abstract Builder buildD(String msg);
abstract Product getProduct();
}
----------------------------------------------------------------------
public class Worker extends Builder {
private Product product;
public Worker() {
product = new Product();
}
@Override
Builder buildA(String msg) {
product.setA(msg);
return this;
}
@Override
Builder buildB(String msg) {
product.setB(msg);
return this;
}
@Override
Builder buildC(String msg) {
product.setC(msg);
return this;
}
@Override
Builder buildD(String msg) {
product.setD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
----------------------------------------------------------------------
public class Test {
public static void main(String[] args) {
Worker worker = new Worker();
Product product = worker.getProduct();
System.out.println(product.toString());
Product product1 = worker.buildA("龙井").buildB("肉蛋肠").getProduct();
System.out.println(product1.toString());
}
}
Product{A='乌龙茶', B='鸡蛋肠', C='虾饺', D='小笼包'}
Product{A='龙井', B='肉蛋肠', C='虾饺', D='小笼包'}
小结
- 优点
- 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必知道产品内部组成的细节
- 将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰
- 具体的建造者类之间是相互独立的,这有利于系统的扩展,增加新的具体建造者无需修改原有类库的代码,符合开闭原则
- 缺点
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大
- 应用场景:
(1)需要生产的产品对象有复杂的内部结构,这些产品对象具备共性
(2)隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品
(3)适合于一个具有较多的零件(属性)的产品(对象)的创建过程 - 建造者模式和抽象工厂模式两个都是创建型的设计方法,那这两者之间有什么不同呢?
- 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族
- 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象
- 如果将抽象工厂模式看成一个电子零件生产工厂,生产一个产品族的产品,那么建造者模式就是一个电子产品组装工厂,通过对部件的组装可以返回一个完整的电子产品
应用实例
- 在JDK中 的应用实例 – StringBuilder
Appendable接口
定义了多个append()
方法(抽象方法), 即Appendable 为抽象建造者, 定义了抽象方法AbstractStringBuilder
实现了 Appendable 接口
方法,这里的 AbstractStringBuilder 已经是建造者,只是不能实例化StringBuilder
既充当了指挥者角色,同时充当了具体的建造者,建造方法的实现是由AbstractStringBuilder
完成, 而StringBuilder
继承了AbstractStringBuilder
