在軟體開發中,我們經常需要建立複雜的物件,這些物件可能包含多個組成部分,並且需要按照一定的步驟進行組裝。如果直接在程式碼中硬編碼物件的建立邏輯,會導致程式碼冗長、難以維護,並且不利於擴充套件。建造者模式提供了一種優雅的解決方案,它將物件的建立過程抽象成一個獨立的建造者類別,使得我們可以逐步地構建物件,並且可以輕鬆地建立不同組態的物件。例如,在本文的披薩製作範例中,我們可以使用建造者模式來建立不同口味、不同配料的披薩,而無需修改核心程式碼。

披薩製作過程

from enum import Enum
import time

# 定義披薩的製作進度
class PizzaProgress(Enum):
    preparing = 1
    baking = 2
    done = 3

# 定義披薩的配料
class PizzaTopping(Enum):
    double_mozzarella = 1
    oregano = 2

class Pizza:
    def __init__(self):
        self.topping = []

class PizzaBuilder:
    def __init__(self):
        self.pizza = Pizza()
        self.baking_time = 5  # 預設烘烤時間為5秒

    def add_topping(self, topping_desc, topping_items):
        print(f'新增配料({topping_desc})到你的馬格麗特披薩')
        self.pizza.topping.append([t for t in topping_items])
        time.sleep(1)  # 假設新增配料需要1秒
        print(f'完成新增配料({topping_desc})')

    def bake(self):
        self.progress = PizzaProgress.baking
        print(f'正在烘烤你的馬格麗特披薩{self.baking_time}秒')
        time.sleep(self.baking_time)  # 假設烘烤時間為5秒
        print('完成烘烤')

    def build(self):
        return self.pizza

# 使用Builder Pattern建立披薩
builder = PizzaBuilder()
builder.add_topping('double mozzarella, oregano', [PizzaTopping.double_mozzarella, PizzaTopping.oregano])
builder.bake()
pizza = builder.build()

print('完成建立披薩')

Builder Pattern的優點

  1. 分離複雜物件的建立和表示:Builder Pattern允許你分離複雜物件的建立和表示,這使得物件的建立過程更加靈活和易於維護。
  2. 提高物件的可重用性:透過使用Builder Pattern,你可以建立多個具有不同組態的物件,而不需要為每個組態建立一個新的類別。
  3. 減少物件的建立過程中的錯誤:Builder Pattern可以幫助你減少物件的建立過程中的錯誤,因為它強制你按照特定的步驟建立物件。

Builder Pattern的實際應用

Builder Pattern在實際應用中非常廣泛,例如:

  • 資料函式庫查詢:你可以使用Builder Pattern建立資料函式庫查詢,透過新增不同的條件和過濾器來構建查詢。
  • 檔案生成:你可以使用Builder Pattern建立檔案,透過新增不同的章節和內容來構建檔案。
  • 網路請求:你可以使用Builder Pattern建立網路請求,透過新增不同的引數和頭部來構建請求。

自訂披薩建造者模式

在這個範例中,我們將實作一個披薩建造者模式,讓使用者可以自訂自己的披薩。首先,我們定義了一個 Pizza 類別,代表一份披薩。

class Pizza:
    def __init__(self, name):
        self.name = name
        self.dough = None
        self.sauce = None
        self.toppings = []

    def prepare_dough(self, dough_type):
        self.dough = dough_type
        print(f"準備{self.dough}的外殼")

    def add_sauce(self, sauce_type):
        self.sauce = sauce_type
        print(f"新增{sauce_type}醬")

    def add_topping(self, topping):
        self.toppings.append(topping)
        print(f"新增{topping}配料")

接下來,我們定義了一個 PizzaProgress 類別,代表披薩的製作進度。

class PizzaProgress:
    queued = "queued"
    preparation = "preparation"
    baking = "baking"
    ready = "ready"

然後,我們定義了一個 CreamyBaconBuilder 類別,繼承自 PizzaBuilder 類別。這個類別負責建造一份奶油培根披薩。

class CreamyBaconBuilder:
    def __init__(self):
        self.pizza = Pizza("creamy bacon")
        self.progress = PizzaProgress.queued
        self.baking_time = 7  # 以秒為單位

    def prepare_dough(self):
        self.progress = PizzaProgress.preparation
        self.pizza.prepare_dough("thick")

    def add_sauce(self):
        print("新增酸奶油醬")
        self.pizza.add_sauce("酸奶油醬")
        time.sleep(1)  # 等待1秒

    def add_topping(self):
        print("新增培根配料")
        self.pizza.add_topping("培根")
        time.sleep(1)  # 等待1秒

最後,我們可以使用 CreamyBaconBuilder 類別來建造一份奶油培根披薩。

builder = CreamyBaconBuilder()
builder.prepare_dough()
builder.add_sauce()
builder.add_topping()
print("您的奶油培根披薩已經完成!")

內容解密:

在這個範例中,我們使用了建造者模式來建造一份披薩。建造者模式是一種設計模式,允許使用者逐步建造複雜的物件。這個範例中,我們定義了一個 Pizza 類別,代表一份披薩,然後定義了一個 CreamyBaconBuilder 類別,負責建造一份奶油培根披薩。使用者可以使用 CreamyBaconBuilder 類別來建造一份奶油培根披薩,並且可以自訂自己的披薩。

圖表翻譯:

  classDiagram
    class Pizza {
        -name: string
        -dough: string
        -sauce: string
        -toppings: list
        +prepare_dough(dough_type: string)
        +add_sauce(sauce_type: string)
        +add_topping(topping: string)
    }
    class PizzaProgress {
        +queued: string
        +preparation: string
        +baking: string
        +ready: string
    }
    class CreamyBaconBuilder {
        -pizza: Pizza
        -progress: string
        -baking_time: int
        +prepare_dough()
        +add_sauce()
        +add_topping()
    }
    Pizza --* CreamyBaconBuilder

這個圖表顯示了 PizzaPizzaProgressCreamyBaconBuilder 類別之間的關係。CreamyBaconBuilder 類別負責建造一份奶油培根披薩,使用 Pizza 類別來代表披薩。

建立披薩的過程:指導者模式

在指導者模式中,指導者(Director)負責管理建造過程,確保所有步驟按照正確的順序執行。以下是建立披薩的過程,使用指導者模式實作:

建立披薩的步驟

  1. 選擇披薩面團:這是建立披薩的第一步,需要選擇合適的面團。
  2. 新增醬料:在面團上新增醬料,例如番茄醬或白醬。
  3. 新增乳酪:新增乳酪,例如莫扎里拉乳酪。
  4. 新增配料:新增配料,例如培根、火腿、蘑菇等。
  5. 烘烤披薩:將披薩放入烤箱,按照設定的時間和溫度烘烤。

指導者模式實作

from enum import Enum
import time

class PizzaProgress(Enum):
    waiting = 1
    preparing = 2
    baking = 3
    ready = 4

class PizzaTopping(Enum):
    mozzarella = 1
    bacon = 2
    ham = 3
    mushrooms = 4
    red_onion = 5
    oregano = 6

class Pizza:
    def __init__(self):
        self.topping = []
        self.progress = PizzaProgress.waiting

    def add_topping(self, topping):
        self.topping.append(topping)

    def bake(self, baking_time):
        self.progress = PizzaProgress.baking
        print(f"烘烤披薩 {baking_time} 秒")
        time.sleep(baking_time)
        self.progress = PizzaProgress.ready
        print("披薩已經完成")

class Waiter:
    def __init__(self):
        self.pizza = Pizza()

    def construct_pizza(self, builder):
        builder.prepare_pizza(self.pizza)
        builder.add_topping(self.pizza)
        builder.bake_pizza(self.pizza)

    def pizza(self):
        return self.pizza

class PizzaBuilder:
    def prepare_pizza(self, pizza):
        print("準備披薩")
        # 準備披薩的步驟

    def add_topping(self, pizza):
        topping_desc = 'mozzarella, bacon, ham, mushrooms, red onion, oregano'
        topping_items = (PizzaTopping.mozzarella,
                          PizzaTopping.bacon,
                          PizzaTopping.ham,
                          PizzaTopping.mushrooms,
                          PizzaTopping.red_onion,
                          PizzaTopping.oregano)
        print(f"新增配料 ({topping_desc})")
        pizza.add_topping([t for t in topping_items])

    def bake_pizza(self, pizza):
        pizza.bake(10)

# 使用指導者模式建立披薩
waiter = Waiter()
builder = PizzaBuilder()
waiter.construct_pizza(builder)
pizza = waiter.pizza()
print("披薩已經完成")

在這個例子中,Waiter 類別是指導者,負責管理建立披薩的過程。PizzaBuilder 類別是建造者,負責實作建立披薩的步驟。Pizza 類別是被建造的物件,代表一份披薩。

建立披薩訂單應用程式

在本節中,我們將實作一個簡單的披薩訂單應用程式,使用建造者(Builder)模式來建立不同款式的披薩。

披薩建造者模式

首先,我們定義一個抽象的披薩建造者類別 PizzaBuilder,它包含了建立披薩的基本步驟:

class PizzaBuilder:
    def prepare_dough(self):
        pass

    def add_sauce(self):
        pass

    def add_topping(self):
        pass

    def bake(self):
        pass

    @property
    def pizza(self):
        pass

接下來,我們實作兩種不同的披薩建造者:MargaritaBuilderCreamyBaconBuilder

class MargaritaBuilder(PizzaBuilder):
    def prepare_dough(self):
        print("Preparing margarita dough...")

    def add_sauce(self):
        print("Adding margarita sauce...")

    def add_topping(self):
        print("Adding margarita topping...")

    def bake(self):
        print("Baking margarita pizza...")

    @property
    def pizza(self):
        return "Margarita Pizza"

class CreamyBaconBuilder(PizzaBuilder):
    def prepare_dough(self):
        print("Preparing creamy bacon dough...")

    def add_sauce(self):
        print("Adding creamy bacon sauce...")

    def add_topping(self):
        print("Adding creamy bacon topping...")

    def bake(self):
        print("Baking creamy bacon pizza...")

    @property
    def pizza(self):
        return "Creamy Bacon Pizza"

披薩訂單應用程式

現在,我們可以建立一個披薩訂單應用程式,使用建造者模式來建立不同款式的披薩:

class PizzaOrderApp:
    def __init__(self):
        self.builder = None

    def construct_pizza(self, builder):
        self.builder = builder
        steps = (builder.prepare_dough,
                  builder.add_sauce,
                  builder.add_topping,
                  builder.bake)
        [step() for step in steps]

    @property
    def pizza(self):
        return self.builder.pizza

def validate_style(builders):
    try:
        input_msg = 'What pizza would you like, [m]argarita or [c]reamy bacon? '
        pizza_style = input(input_msg)

        builder = builders[pizza_style]()

        valid_input = True
    except KeyError:
        error_msg = 'Sorry, only margarita (key m) and creamy bacon (key c) are available'
        print(error_msg)
        return (False, None)

    return (True, builder)

def main():
    builders = {
        'm': MargaritaBuilder,
        'c': CreamyBaconBuilder
    }

    valid_input, builder = validate_style(builders)

    if valid_input:
        app = PizzaOrderApp()
        app.construct_pizza(builder)
        print(f"Your pizza is: {app.pizza}")

if __name__ == "__main__":
    main()

執行結果

當我們執行這個應用程式時,系統會提示使用者輸入披薩款式:

What pizza would you like, [m]argarita or [c]reamy bacon? 

如果使用者輸入 m,系統會建立一份 Margarita Pizza:

Preparing margarita dough...
Adding margarita sauce...
Adding margarita topping...
Baking margarita pizza...
Your pizza is: Margarita Pizza

如果使用者輸入 c,系統會建立一份 Creamy Bacon Pizza:

Preparing creamy bacon dough...
Adding creamy bacon sauce...
Adding creamy bacon topping...
Baking creamy bacon pizza...
Your pizza is: Creamy Bacon Pizza

這個應用程式示範了建造者模式的應用,讓使用者可以輕鬆建立不同款式的披薩。

建立者模式的實作

介紹

建立者模式是一種設計模式,允許您分步驟地構建複雜物件。它提供了一種方法來將物件的構建和表示分離,使得您可以更容易地修改和擴充套件物件的構建過程。

實作細節

以下是建立者模式的實作細節:

  1. 匯入必要的模組:我們需要匯入 Enum 類別和 time 模組。
  2. 定義常數:我們定義了一些常數,例如 PizzaProgressPizzaDoughPizzaSaucePizzaToppingSTEP_DELAY
  3. 定義 Pizza 類別:我們定義了一個 Pizza 類別,代表了一個披薩物件。
  4. 定義建立者類別:我們定義了兩個建立者類別,MargaritaBuilderCreamyBaconBuilder,這些類別負責構建不同的披薩型別。
  5. 定義 Waiter 類別:我們定義了一個 Waiter 類別,負責接收使用者的輸入和顯示最終的披薩物件。

程式碼實作

以下是程式碼實作的詳細內容:

import enum
import time

# 定義常數
class PizzaProgress(enum.Enum):
    DOUGH = 1
    SAUCE = 2
    TOPPING = 3
    BAKED = 4

class PizzaDough:
    def __init__(self):
        self.dough = "薄餅"

class PizzaSauce:
    def __init__(self):
        self.sauce = "番茄醬"

class PizzaTopping:
    def __init__(self):
        self.topping = "莫扎里拉乳酪"

STEP_DELAY = 2

# 定義 Pizza 類別
class Pizza:
    def __init__(self):
        self.progress = PizzaProgress.DOUGH
        self.dough = PizzaDough()
        self.sauce = PizzaSauce()
        self.topping = PizzaTopping()

    def __str__(self):
        return f"披薩 ({self.progress.name})"

# 定義建立者類別
class MargaritaBuilder:
    def __init__(self):
        self.pizza = Pizza()

    def add_dough(self):
        self.pizza.dough = PizzaDough()
        self.pizza.progress = PizzaProgress.SAUCE
        time.sleep(STEP_DELAY)

    def add_sauce(self):
        self.pizza.sauce = PizzaSauce()
        self.pizza.progress = PizzaProgress.TOPPING
        time.sleep(STEP_DELAY)

    def add_topping(self):
        self.pizza.topping = PizzaTopping()
        self.pizza.progress = PizzaProgress.BAKED
        time.sleep(STEP_DELAY)

class CreamyBaconBuilder:
    def __init__(self):
        self.pizza = Pizza()

    def add_dough(self):
        self.pizza.dough = PizzaDough()
        self.pizza.progress = PizzaProgress.SAUCE
        time.sleep(STEP_DELAY)

    def add_sauce(self):
        self.pizza.sauce = PizzaSauce()
        self.pizza.progress = PizzaProgress.TOPPING
        time.sleep(STEP_DELAY)

    def add_topping(self):
        self.pizza.topping = PizzaTopping()
        self.pizza.progress = PizzaProgress.BAKED
        time.sleep(STEP_DELAY)

# 定義 Waiter 類別
class Waiter:
    def __init__(self):
        self.pizza = None

    def pizza(self):
        return self.pizza

# 主函式
def main():
    builders = dict(m=MargaritaBuilder, c=CreamyBaconBuilder)

    valid_input = False

    while not valid_input:
        valid_input, builder = validate_style(builders)

    print()

    waiter = Waiter()

    pizza = waiter.pizza

    print()

    print(f'Enjoy your {pizza}!')

if __name__ == "__main__":
    main()

建造者模式的應用

在軟體開發中,建造者模式是一種常用的設計模式,尤其是在需要建立複雜物件的情況下。這種模式允許我們將物件的建立和表示分離,使得程式碼更加靈活和易於維護。

從程式碼實作到應用場景的全面檢視顯示,建造者模式有效地解決了複雜物件建立過程中的混亂和冗餘。透過將物件的組裝過程分解成多個步驟,並由建造者類別負責執行,我們可以清晰地控制物件的建立流程。更進一步地,指導者模式的引入,更能簡化客戶端的呼叫邏輯,讓客戶端無需瞭解物件的內部建構細節,即可輕鬆建立所需的物件。

然而,建造者模式並非沒有限制。當物件的結構過於簡單,或者只需要建立少量物件時,使用建造者模式反而可能增加程式碼的複雜度。此外,如果物件的屬性之間存在強烈的依賴關係,建造者模式的彈性優勢也會受到限制。對於這些情況,需要仔細權衡使用建造者模式的利弊。

展望未來,建造者模式在領域驅動設計(DDD)和微服務架構中將扮演更重要的角色。隨著系統複雜度的提升,物件的建立邏輯也將更加複雜。建造者模式可以幫助我們更好地管理這種複雜性,提高程式碼的可讀性和可維護性。同時,結合函式式程式設計的思想,建造者模式可以進一步提升物件建立的效率和靈活性。

對於追求程式碼品質和可維護性的開發團隊,深入理解並應用建造者模式將是提升軟體設計水平的關鍵一步。建議開發團隊在設計複雜物件的建立流程時,優先考慮使用建造者模式,並根據實際情況選擇合適的變體和最佳實踐,以最大程度地發揮其優勢。