# 建造者模式

## 模式说明

有一些对象，他们由多个部件构成，构成的方式相同，但每个部件在不同对象中可能有不同的特征细节。举例来说，无论是哪个品牌的电脑，都由CPU，显示器，硬盘内存，键盘等部件构成，只是对不同品牌不同型号的PC，部件的细节不同，例如苹果电脑的CPU是苹果自研的，联想电脑CPU是英特尔的。在客户端中完成对不同对象的建造，最直接的方式是分别声明他们，然后调用各自的建造动作来完成。这样的做法无法利用不同对象建造过程稳定且相同(只是细节不同)的特点，达不到代码复用的效果。针对这种场景，可以使用建造者模式来实现。

建造者模式提供一个抽象建造者类，类内定义了稳定的产品建造过程，即建造具体产品各部件的抽象方法。这样具体建造者继承抽象建造者类后，可以根据需要重写某些部件的建造方法。具体建造者类内持有一个产品类实例，用于保存建造完成后的产品，并通过他的getter的方法获取该产品的实例。展示产品细节的动作在产品类中完成，这就是所谓的将复杂对象(即本模式中的产品类)的构造和表示分离，实际就是建造者类(负责产品建造)和产品类(负责表示)分离。客户端发起产品建造时，可以声明一个具体建造类，并调用其建造过程(多个部件的`build`方法)，但这样一来就对客户端暴露了建造过程，且加重了客户端的任务。避免这个缺点的办法是另外设置一个指挥者类，该类只有一个`produce`方法，方法参数是具体建造者实例，传入该实例，在`produce`内部调用该实例建造各部件的方法。通过设置指挥者类，将本来暴露在客户端中的建造者对建造过程的调用转移到了指挥者类内部。至此，客户端只需要声明一个指挥者，再声明一个具体建造者，将具体建造者作为指挥者的`produce`方法参数，指挥者执行其`produce`完成建造。执行后需要查看得到的产品细节，再调用产品建造者的`getProduce`方法即可。

本示例以汽车生产为例，展示如何利用建造者模式来生产F1赛车和普通家用汽车。

<br>

## 结构

**指挥者类**: 提供一个指挥生产的方法`produce`，传入建造者，其内调用建造者的建造方法。 **抽象建造者类**: 提供建造产品各部件的抽象方法和一个返回产品的方法。 **具体建造者类**: 继承抽象建造者类，并持有一个产品实例以供获取。实现产品各部分抽象建造方法和返回产品的抽象方法。 **产品类**: 持有产品各部件的一个集合实例，有一个增加部件的`add`方法，一个用于展现组成部件的`show`方法。

<br>

## 代码演示

```java
package com.yukiyama.pattern.creation;

import java.util.ArrayList;
import java.util.List;

/**
 * 建造者模式(生成器模式)
 */
public class BuilderDemo {

    public static void main(String[] args) {
        // 声明一个指挥者
        Director director = new Director();
        // 声明一个具体建造者
        CarMaker carMaker = new F1CarMaker();
        // 指挥者执行produce方法，传入具体建造者执行建造
        director.produce(carMaker);
        // 通过建造者的get方法得到建造后的产品
        Car car = carMaker.getCar();
        // 产品调用show方法展示建造后的产品细节
        car.show();
    }

}

/**
 * 指挥者类
 * 提供一个指挥生产的方法produce，传入具体建造者，执行既定的建造产品的方法
 * 完成产品制造。
 */
class Director{
    public void produce(CarMaker cm) {
        cm.buildWheels();
        cm.buildEngine();
        cm.buildSeats();
    }
}

/**
 * 抽象建造者类
 * 提供建造产品各部件的抽象方法和一个返回产品的方法。
 * 下例为一个抽象汽车制造者类。
 */
abstract class CarMaker{
    public abstract void buildWheels();
    public abstract void buildEngine();
    public abstract void buildSeats();
    public abstract Car getCar();
}

/**
 * 具体建造者类
 * 继承抽象建造者类，并持有一个产品实例，实现产品各部分抽象建造方法和返回
 * 产品的抽象方法(返回其持有的产品实例)。
 * 下例是F1赛车制造者
 */
class F1CarMaker extends CarMaker{
    private Car car = new Car();
    
    @Override
    public void buildWheels() {
        car.add("赛车轮胎");
    }
    @Override
    public void buildEngine() {
        car.add("赛车引擎");
    }
    @Override
    public void buildSeats() {
        car.add("赛车座椅");
    }
    @Override
    public Car getCar() {
        return car;
    }
}

/**
 * 具体建造者类
 * 按照该建造者的实际情况实现产品各部分建造方法和返回产品方法
 * 下例是家用车制造者
 */
class HomeCarMaker extends CarMaker{
    private Car car = new Car();
    
    @Override
    public void buildWheels() {
        car.add("家用车轮胎");
    }
    @Override
    public void buildEngine() {
        car.add("家用车引擎");
    }
    @Override
    public void buildSeats() {
        car.add("家用车座椅");
    }
    @Override
    public Car getCar() {
        return car;
    }
}

/**
 * 要建造的产品类
 * 持有产品各部件的集合List<String>，定义一个add方法用于添加构件。另定义
 * 一个show方法用于展示建造的产品细节。
 */
class Car{
    private List<String> parts = new ArrayList<>();
    
    public void add(String part) {
        parts.add(part);
    }
    public void show() {
        System.out.println(parts);
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://iyukiyama.gitbook.io/design-pattern/chuang-jian-xing-she-ji-mo-shi/jian-zao-zhe-mo-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
