建造者模式的主要目的是将一个复杂对象的构建过程封装起来,使得客户端代码不需要知道对象创建的细节。这种模式特别适用于那些具有多个组成部分、创建过程复杂、对象属性多且大多数属性可选的场合。

在Java中,建造者模式通常涉及以下几个角色:

  • Builder(建造者):为创建一个Product对象的各个部件指定抽象接口。
  • ConcreteBuilder(具体建造者):实现Builder的接口以构造和装配该产品的各个部件。定义并明确它所创建的表示,并提供一个检索产品的接口。
  • Director(指挥者):构造一个使用Builder接口的对象。
  • Product(产品):表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
  • Client(客户端):创建一个Director对象,并用它所想要的Builder对象来配置。

以下是建造示例产品的代码:Product类表示复杂对象,Builder类是抽象建造者类,ConcreteBuilder1和ConcreteBuilder2是具体的建造者类,buildPartA;b;c用来代指构建产品的不同部分,Director类负责指挥构建过程,Client类是客户端代码。

我们用图像来表示各个类之间的关系:

掌握Java建造者模式:逐步构建复杂对象的艺术与实践_客户端

先构建Product产品类:

class Product {
    private String partA;
    private String partB;
    private String partC;

    public void setPartA(String partA) {
        this.partA = partA;
    }

    public void setPartB(String partB) {
        this.partB = partB;
    }

    public void setPartC(String partC) {
        this.partC = partC;
    }

    public void show() {
        System.out.println("Product: " + partA + ", " + partB + ", " + partC);
    }
}

抽象建造者类:

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;
    }
}

具体建造者类1:

class ConcreteBuilder1 extends Builder {
    public void buildPartA() {
        product.setPartA("Part A1");
    }

    public void buildPartB() {
        product.setPartB("Part B1");
    }

    public void buildPartC() {
        product.setPartC("Part C1");
    }
}

具体建造者类2:

class ConcreteBuilder2 extends Builder {
    public void buildPartA() {
        product.setPartA("Part A2");
    }

    public void buildPartB() {
        product.setPartB("Part B2");
    }

    public void buildPartC() {
        product.setPartC("Part C2");
    }
}

指挥者类:

class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public void construct() {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
    }
}

客户端代码:

public class BuilderPatternDemo {
    public static void main(String[] args) {
        Builder builder1 = new ConcreteBuilder1();
        Director director1 = new Director(builder1);
        director1.construct();
        Product product1 = builder1.getResult();
        product1.show();

        Builder builder2 = new ConcreteBuilder2();
        Director director2 = new Director(builder2);
        director2.construct();
        Product product2 = builder2.getResult();
        product2.show();
    }
}

适用场景

  1. 对象结构复杂:当一个对象有很多属性,且内部结构非常复杂时,使用建造者模式可以将这些属性的构建过程封装起来,使得客户端代码不需要直接处理这些复杂性。
  2. 构建步骤多:如果创建一个对象需要很多步骤,尤其是在这些步骤之间有依赖关系或者某些步骤可以省略时,建造者模式可以将这些步骤分离,使得每一步都可以独立执行,同时也允许不同的步骤组合来创建不同的对象表示。
  3. 创建与使用分离:在希望将对象的创建过程与它的使用过程分离时,建造者模式提供了一种机制,使得客户端代码可以在不了解对象内部细节的情况下,通过指定的步骤创建出所需的对象。

JDK中的建造者模式

  1. StringBuilder 类:StringBuilder 类提供了 append() 方法,允许链式调用来构建字符串。这种方式避免了多次创建字符串对象,提高了效率。StringBuilder 就是通过建造者模式来实现这一链式创建对象的过程。
  2. ProcessBuilder 类:ProcessBuilder 类用于创建操作系统进程。它也提供了一种流畅的接口,允许开发者通过连续调用方法来设置进程的各种属性,最后通过 start() 方法来启动进程。ProcessBuilder 的这种使用方式也是建造者模式的一个体现。

优点

  1. 封装性良好:建造者模式通过将复杂对象的创建过程封装在建造者类中,实现了创建过程和使用过程的分离。这样做的好处是,客户端代码不需要知道对象是如何一步步构建起来的,只需要知道如何组合这些步骤即可。这不仅使得客户端代码更加简洁,也降低了出错的可能性。
  2. 扩展性良好:由于建造者类之间相互独立,这在一定程度上实现了解耦。当需要增加新的构建步骤或者修改现有步骤时,只需修改相应的建造者类,而不影响其他类。这种设计提高了系统的可维护性和可扩展性。
  3. 简化复杂对象的创建:对于参数多、校验复杂的对象创建过程,建造者模式提供了一种清晰且易于理解的方式来逐步构建对象。这种方法特别适用于那些构造函数参数众多,或者对象创建过程需要多个步骤的情况。
  4. 提高代码的可读性和可维护性:建造者模式使得代码的结构更加清晰,每个建造者类负责一部分构建逻辑,这有助于提高代码的可读性和可维护性。

缺点

  1. 增加类的数量:为了实现复杂对象的构建,可能需要引入多个建造者类,这会增加系统中类的总数。
  2. 内部修改困难:如果产品类的内部结构或构建过程发生变化,可能需要修改建造者类,这可能会导致维护上的困难。
  3. 范围限制:建造者模式要求产品具有共同点,这限制了它的使用范围。如果产品的内部变化非常复杂,可能会导致建造者类的数量增加,从而使得系统变得更加复杂。

建造者模式和工厂模式区别

  1. 目的不同:建造者模式关注于创建复杂对象的构建过程,将构建过程和表示分离,以便可以逐步构建复杂对象。工厂模式关注于对象的创建,将对象的创建过程封装在工厂中,以便在客户端中使用。
  2. 构造过程不同:建造者模式注重的是部件构建的过程,旨在通过一步一步地精确构造创建出一个复杂的对象。工厂模式一般都是创建一个产品,注重的是把这个产品创建出来就行,只要创建出来,不关心这个产品的组成部分。