建造模式

建造模式

建造模式是一种创建型设计模式,它将一个复杂对象的构建与其表示分离。它允许你通过一步一步地构建对象来创建不同的表示。它通常用于创建复杂的对象。

建造模式有如下优点:

  • 将复杂对象的构建与表示分离。
  • 可以更容易地创建不同的表示。
  • 可以方便地扩展新类型。

结构 #

建造模式包含以下角色:

  • 抽象建造者(Builder): 定义一个接口,指定构建复杂对象各个部分的步骤。
  • 具体建造者(ConcreteBuilder): 实现抽象建造者接口,具体实现构建复杂对象的步骤。
  • 指挥者(Director): 负责调用具体建造者的方法,构建复杂对象。
  • 产品(Product): 最终构建出来的复杂对象。

UML简图 #

classDiagram
direction LR
  class Builder {
    << interface >>
    +buildPartA()
    +buildPartB()
    +buildPartC()
    +getResult()
  }
  class ConcreteBuilder1 {
    +buildPartA()
    +buildPartB()
    +buildPartC()
    +getResult()
  }
  class ConcreteBuilder2 {
    +buildPartA()
    +buildPartB()
    +buildPartC()
    +getResult()
  }
  class Director {
    +construct()
  }
  class Product {
    +partA
    +partB
    +partC
  }

  Builder <|.. ConcreteBuilder1
  Builder <|.. ConcreteBuilder2
  Director --> Builder
  Director --> Product
  Product ..> ConcreteBuilder1
  Product ..> ConcreteBuilder2

示例代码 #

本示例中我们使用建造模式来创建一部车,一部车显然是一个“复杂”的对象,可以将它的创建分成不同的部分,比如座椅,引擎,行车电脑等等不同的模块。我们使用建造模式来创建一个“车”对象。

建造者及其实现 #

建造者是一个接口,提供了创建对象的而步骤,具体的实现细节,可以由具体的子类控制。特别注意的是,Builder提供了两个重要的方法:

  • reset()
  • getProduct()

第一个方法用来重置构建器的这种参数,为下一次的构建做准备。

第二个方法顾名思义,用来获取产品。

 1public interface Builder {
 2    void reset();
 3
 4    void setSeats(int seats);
 5
 6    void setEngine(Engine engine);
 7
 8    void setTripComputer(boolean computer);
 9
10    void setGPS(boolean gps);
11
12    Product getProduct();
13}
14
15public class CarBuilder implements Builder {
16
17    private Car car;
18    private Product product;
19
20    public CarBuilder() {
21        this.reset();
22    }
23
24    @Override
25    public void reset() {
26        this.car = new Car();
27    }
28
29    @Override
30    public void setSeats(int seats) {
31        car.setSeat(seats);
32    }
33
34    @Override
35    public void setEngine(Engine engine) {
36        car.setEngine(engine);
37    }
38
39    @Override
40    public void setTripComputer(boolean bool) {
41        car.setTripComputer(bool);
42    }
43
44    @Override
45    public void setGPS(boolean gps) {
46        car.setGPS(gps);
47    }
48
49    // 具体构建器需要自行提供获取结果的方法。这是因为不同类型的构建器可能
50    // 会创建不遵循相同接口的、完全不同的产品。所以也就无法在生成器接口中
51    // 声明这些方法(至少在静态类型的编程语言中是这样的)。
52    //
53    // 通常在构建器实例将结果返回给客户端后,它们应该做好生成另一个产品的
54    // 准备。因此生成器实例通常会在 `getProduct(获取产品)`方法主体末尾
55    // 调用重置方法。但是该行为并不是必需的,你也可让生成器等待客户端明确
56    // 调用重置方法后再去处理之前的结果。
57    @Override
58    public Car getProduct() {
59        this.product = this.car;
60        this.reset();
61        return (Car) product;
62    }
63}

产品 #

产品,也就是我们最终要创建的对象,本例中,是一部车。

 1public interface Product {
 2
 3}
 4
 5public class Car implements Product {
 6    private int seat;
 7
 8    private Engine engine;
 9
10    private boolean tripComputer;
11
12    private  boolean GPS;
13
14    public void setSeat(int seat) {
15        this.seat = seat;
16    }
17
18    public void setEngine(Engine engine) {
19        this.engine = engine;
20    }
21
22    public void setTripComputer(boolean tripComputer) {
23        this.tripComputer = tripComputer;
24    }
25
26    public void setGPS(boolean GPS) {
27        this.GPS = GPS;
28    }
29
30    public int getSeat() {
31        return seat;
32    }
33
34    public Engine getEngine() {
35        return engine;
36    }
37
38    public boolean isTripComputer() {
39        return tripComputer;
40    }
41
42    public boolean isGPS() {
43        return GPS;
44    }
45
46    @Override
47    public String toString() {
48        return "Car{" +
49            "seat=" + seat +
50            ", engine=" + engine +
51            ", tripComputer=" + tripComputer +
52            ", GPS=" + GPS +
53            '}';
54    }
55}

在创建产品的过程中,很容易产生一些中间类型,本例中,“引擎”就是中间类型。此处代码做了极简处理。

1public interface Engine {
2}
3
4class NormalEngine implements Engine{
5}
6
7class SportEngine implements Engine{
8}
9

指挥者 #

有了建造者和产品,需要控制产品的生成。那么就轮到Director出场了,它负责组装产品:

 1public class CarDirector {
 2
 3    private  Builder builder;
 4
 5    public Builder getBuilder() {
 6        return builder;
 7    }
 8
 9    void createSportCar(Builder builder){
10        builder.reset();
11        builder.setSeats(2);
12        builder.setEngine(new SportEngine());
13        builder.setTripComputer(true);
14        builder.setGPS(true);
15    }
16
17
18    void createSUV(Builder builder){
19        builder.reset();
20        builder.setSeats(7);
21        builder.setEngine(new NormalEngine());
22        builder.setTripComputer(true);
23        builder.setGPS(true);
24    }
25}

测试代码 #

 1public class TestBuilder {
 2
 3    public static void main(String[] args) {
 4        CarDirector carDirector = new CarDirector();
 5        CarBuilder builder = new CarBuilder();
 6        //create sport car
 7        carDirector.createSportCar(builder);
 8        System.out.println(builder.getProduct());
 9        // create suv
10        carDirector.createSUV(builder);
11        System.out.println(builder.getProduct());
12    }
13}
14///:~
15//Car{seat=2, engine=*.SportEngine@90f6bfd, tripComputer=true, GPS=true}
16//Car{seat=7, engine=*.NormalEngine@15975490, tripComputer=true, GPS=true}

建造模式和工厂模式的区别 #

Generated by chatgpt.

建造者模式Builder Pattern)和工厂模式Factory Pattern,包括简单工厂模式、工厂方法模式和抽象工厂模式)都是用来创建对象的设计模式,但它们在意图、应用场景和实现方式上有所不同。

  1. 建造者模式

    建造者模式主要用于创建一种复杂的对象,其产品通常需要多个部分按特定的过程组合而成。这种模式允许用户通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节

    • 意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
    • 应用场景:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时;当构造过程必须允许被构造的对象有不同的表示时。
    • 实现方式:通常由Director(指挥者)、Builder(建造者接口)、ConcreteBuilder(具体建造者)和Product(产品)组成。客户端创建Director对象,并用它所需要的Builder对象进行配置。Director决定如何以及何时让建造者产生部件,然后组合成产品返回。
  2. 工厂模式

    工厂模式主要用于创建对象,特别是在创建某个类的对象时不希望指定确切的类。工厂模式通过调用一个工厂方法而不是直接调用构造函数来创建对象(可能是指定的接口或抽象类的具体实现)。

    • 意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
    • 应用场景:当一个类不知道它所必须创建的对象的类的时候;当一个类希望由它的子类来指定创建的对象时;当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪个帮助子类是代理者这一信息局部化时。
    • 实现方式:可以分为三种:
    • 简单工厂模式:不属于GOF的23种设计模式,它实际上是一种编程习惯。一个工厂类根据传入的参数决定创建出哪一种产品类的实例。
    • 工厂方法模式:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。使用一个类的实例来创建另一个类的实例。
    • 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
  3. 总结

  • 目的不同:
    • 建造者模式主要用于创建复杂对象,强调的是一步步构造一个复杂对象,可以用不同的组合或顺序得到不同的结果。
    • 工厂模式主要用于创建类型族的对象,强调的是为客户端提供一个创建对象的接口,隐藏创建逻辑。
  • 应用场景不同:
    • 建造者模式适用于那些产品对象的内部结构比较复杂,需要多步骤构建的场景。
    • 工厂模式适用于创建对象时,不希望客户端知道创建逻辑的场景。
  • 实现复杂度不同: 建造者模式的实现比工厂模式复杂,因为它通常需要多个步骤来创建一个对象,而工厂模式通常通过调用一个方法就可以直接创建对象。

选择哪种模式取决于具体需求,如果需要更加精细和控制的对象创建过程,建造者模式可能是更好的选择。如果只是需要一个简单的接口来创建一系列相关或依赖的对象,工厂模式可能更适合。