建造者模式

<image>

在面向對象編程中，建造者模式（builder pattern），也譯為生成器模式，是一種對象構建設計模式。它可以將複雜對象的建造過程抽象出來（抽象類別），使這個抽象過程的不同實現方法可以構造出不同表現（屬性）的對象。

## 概述

建造者模式所適用的情況：當創建複雜對象的演算法應該獨立於該對象的組成部分以及它們的裝配方式之時；當構造過程必須允許被構造的對象有不同的表示之時。建造者模式的效果：可以改變一個產品的內部表示，將構造代碼和表示代碼分開，可對構造過程進行更精細的控制。

它需要注意如下一些問題。

- 裝配和構造接口：建造者逐步的構造它們的產品，因此建造者介面必須足夠普遍，以便為各種類型的具體建造者構造產品。
- 沒有抽象類：通常情況下，由具體建造者生成的產品，它們的表示相差是如此之大以至於給不同的產品以公共父類沒有太大意思。
- 在建造者中預設的方法為空：定義為空方法可以使客戶只重定義他們所感興趣的操作。

抽象工廠模式與建造者相似，因為它也可以創建複雜對象。主要的區別是建造者模式著重於一步步構造一個複雜對象。而抽象工廠模式著重於多個系列的產品對象（簡單的或是複雜的）。建造者在最後的一步返回產品，而對於抽象工廠來說，產品是立即返回的。合成模式的複雜對象通常是可用建造者生成的。

## 結構

<image>

在上面的UML類圖中，`Director`類不直接的創建並組裝`ProductA1`和`ProductB1`對象。`Director`轉而提及`Builder`接口來建造（創建並組裝）一個複雜對象的各部份，這使得`Director`獨立於哪個具體類要被初始化（哪個表示要被創建）。`Builder1`類通過創建並組裝`ProductA1`和`ProductB1`對象來實現`Builder`接口。

UML序列圖展示了運行時交互：`Director`對象調用`buildPartA()`於`Builder1`對象之上，它創建並組裝`ProductA1`對象。此後，`Director`調用`buildPartB()`於`Builder1`之上，它創建並組裝`ProductB1`對象。

### 參與者

- Builder：為創建一個Product對象的各個部件指定抽象接口。
- ConcreteBuilder：實現Builder的接口以構造和裝配該產品的各個部件。定義並明確它所創建的表示。提供一個檢索產品的接口。
- Director：構造一個使用Builder接口的對象。
- Product：表示被構造的複雜對象。包含定義組成部件的類，包括將這些部件裝配成最終產品的接口。ConcreateBuilder創建該產品的內部表示並定義它的裝配過程。

客戶創建Director對象，並用它所想要的Builder對象進行配置。

- 一旦產品部件被生成，指導者就會通知建造者。
- 建造者處理指導者的請求，並將部件添加到該產品中。
- 客戶從建造者中檢索產品。

## 範例

### Java

Java例子：

```java
/** "Product" */
class Pizza {
    private String dough = "";
    private String sauce = "";
    private String topping = "";
 
    public void setDough (String dough)     { this.dough = dough; }
    public void setSauce (String sauce)     { this.sauce = sauce; }
    public void setTopping (String topping) { this.topping = topping; }
}
  
/** "Abstract Builder" */
abstract class PizzaBuilder {
    protected Pizza pizza;
 
    public Pizza getPizza() { return pizza; }
    public void createNewPizzaProduct() { pizza = new Pizza(); }
 
    public abstract void buildDough();
    public abstract void buildSauce();
    public abstract void buildTopping();
}
 
/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
    public void buildDough()   { pizza.setDough("cross"); }
    public void buildSauce()   { pizza.setSauce("mild"); }
    public void buildTopping() { pizza.setTopping("ham+pineapple"); }
}
 
/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
    public void buildDough()   { pizza.setDough("pan baked"); }
    public void buildSauce()   { pizza.setSauce("hot"); }
    public void buildTopping() { pizza.setTopping("pepperoni+salami"); }
}
 
 /** "Director" */
class Waiter {
    private PizzaBuilder pizzaBuilder;
 
    public void setPizzaBuilder (PizzaBuilder pb) { pizzaBuilder = pb; }
    public Pizza getPizza() { return pizzaBuilder.getPizza(); }
 
    public void constructPizza() {
        pizzaBuilder.createNewPizzaProduct();
        pizzaBuilder.buildDough();
        pizzaBuilder.buildSauce();
        pizzaBuilder.buildTopping();
    }
}
 
/** A customer ordering a pizza. */
class BuilderExample {
    public static void main(String[] args) {
        Waiter waiter = new Waiter();
        PizzaBuilder hawaiianPizzabuilder = new HawaiianPizzaBuilder();
        PizzaBuilder spicyPizzabuilder = new SpicyPizzaBuilder();
 
        waiter.setPizzaBuilder ( hawaiianPizzabuilder );
        waiter.constructPizza();
 
        Pizza pizza = waiter.getPizza();
    }
}
```

### C#

C#例子：

```csharp
// Represents a product created by the builder.
public class Bicycle {
    public Bicycle(string maker, string model, string colour, int height) {
        Maker = maker;
        Model = model;
        Colour = colour;
        Height = height;
    }

    public string Maker { get; set; }
    public string Model { get; set; }
    public int Height { get; set; }
    public string Colour { get; set; }
}

// The builder abstraction.
public interface IBicycleBuilder {
    Bicycle GetResult();

    string Colour { get; set; }
    int Height { get; set; }
}

// Concrete builder implementation.
public class GTBicyclesBuilder : IBicycleBuilder {
    public Bicycle GetResult() {
        return Height == 29 ? new Bicycle("GT Bicycles Inc.", "Avalanche", Colour, Height) : null;
    }

    public string Colour { get; set; }
    public int Height { get; set; }
}

// The director.
public class MountainBikeBuildDirector {
    private IBicycleBuilder _builder;

    public MountainBikeBuildDirector(IBicycleBuilder builder) {
        _builder = builder;
    }

    public void Construct() {
        _builder.Colour = "Red";
        _builder.Height = 29;
    }

    public Bicycle GetResult() {
		return this._builder.GetResult();
	}
}

public class Client {
    public void DoSomethingWithBicycles() {
        var director = new MountainBikeBuildDirector(new GTBicyclesBuilder());
        // Director controls the stepwise creation of product and returns the result.
        director.Construct();
        Bicycle myMountainBike = director.GetResult();
    }
}
```

### Python

Python的例子：

```python
from abc import ABC, abstractmethod
from weakref import WeakKeyDictionary

class Component():
    def __init__(self, name):
        self.name = name
        self.attr_dict = WeakKeyDictionary()
    def __get__(self, obj, objtype=None):
        return (self.attr_dict[obj]
            if obj in self.attr_dict else None)
    def __set__(self, obj, value):
        self.attr_dict[obj] = {'name': self.name} | value
    def __delete__(self, obj):
        if obj in self.attr_dict:
            del self.attr_dict[obj]
    def __call__(self, obj, value=None, *, delete=False):
        if delete is True:
            self.__delete__(obj)
        elif value is None:
            return self.__get__(obj)
        else:
            self.__set__(obj, value)

class Product():
    __part_A = Component('part_A')
    __part_B = Component('part_B')
    __components = [__part_A, __part_B]
    def __len__(self):
        return len(self.__components)
    def __getitem__(self, index):
        return self.__components[index](self)
    def __setitem__(self, index, value):
        self.__components[index](self, value)
    def __delitem__(self, index):
        self.__components[index](self, delete=True)
    @property
    def description(self):
        strlist = [f"{comp['name']}: {comp['builder']}" 
            for comp in self if comp is not None]
        print("{Product: {" + ', '.join(strlist) + "}}")

class Builder(ABC):
    def __init_subclass__(cls, /, params={}, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.params = params
    def __init__(self, **kwargs):
        self.product = Product()
    @abstractmethod
    def build_step_0(self): pass
    @abstractmethod
    def build_step_1(self): pass
    def build(self, **kwargs): 
        self.build_step_0(**kwargs)
        self.build_step_1(**kwargs)
    def get_result(self):
        result, self.product = self.product, None
        return result

class BuilderA(Builder, params={'builder': 'BuilderA'}):
    def build_step_0(self, **kwargs): 
        self.product[0] = type(self).params | kwargs
    def build_step_1(self, **kwargs):
        self.product[1] = type(self).params | kwargs
        
class BuilderB(Builder, params={'builder': 'BuilderB'}):
    def build_step_0(self, **kwargs): 
        self.product[1] = type(self).params | kwargs
    def build_step_1(self, **kwargs):
        self.product[0] = type(self).params | kwargs

class Director():
    def __init__(self, builder_class, **kwargs):
        self.builder_class = builder_class
    def __call__(self, **kwargs):
        self.builder = self.builder_class()
        self.builder.build(kw='')
        result, self.builder = self.builder.get_result(), None
        return result
```

其執行：

```pycon
>>> product1 = Director(BuilderA)()
>>> product1.description
{Product: {part_A: BuilderA, part_B: BuilderA}}
>>> product2 = Director(BuilderB)()
>>> product2.description
{Product: {part_A: BuilderB, part_B: BuilderB}}
```