在軟體開發中,我們經常需要建立複雜的物件,這些物件可能包含多個組成部分,並且需要按照一定的步驟進行組裝。如果直接在程式碼中硬編碼物件的建立邏輯,會導致程式碼冗長、難以維護,並且不利於擴充套件。建造者模式提供了一種優雅的解決方案,它將物件的建立過程抽象成一個獨立的建造者類別,使得我們可以逐步地構建物件,並且可以輕鬆地建立不同組態的物件。例如,在本文的披薩製作範例中,我們可以使用建造者模式來建立不同口味、不同配料的披薩,而無需修改核心程式碼。
披薩製作過程
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的優點
- 分離複雜物件的建立和表示:Builder Pattern允許你分離複雜物件的建立和表示,這使得物件的建立過程更加靈活和易於維護。
- 提高物件的可重用性:透過使用Builder Pattern,你可以建立多個具有不同組態的物件,而不需要為每個組態建立一個新的類別。
- 減少物件的建立過程中的錯誤: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
這個圖表顯示了 Pizza
、PizzaProgress
和 CreamyBaconBuilder
類別之間的關係。CreamyBaconBuilder
類別負責建造一份奶油培根披薩,使用 Pizza
類別來代表披薩。
建立披薩的過程:指導者模式
在指導者模式中,指導者(Director)負責管理建造過程,確保所有步驟按照正確的順序執行。以下是建立披薩的過程,使用指導者模式實作:
建立披薩的步驟
- 選擇披薩面團:這是建立披薩的第一步,需要選擇合適的面團。
- 新增醬料:在面團上新增醬料,例如番茄醬或白醬。
- 新增乳酪:新增乳酪,例如莫扎里拉乳酪。
- 新增配料:新增配料,例如培根、火腿、蘑菇等。
- 烘烤披薩:將披薩放入烤箱,按照設定的時間和溫度烘烤。
指導者模式實作
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
接下來,我們實作兩種不同的披薩建造者:MargaritaBuilder
和 CreamyBaconBuilder
:
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
這個應用程式示範了建造者模式的應用,讓使用者可以輕鬆建立不同款式的披薩。
建立者模式的實作
介紹
建立者模式是一種設計模式,允許您分步驟地構建複雜物件。它提供了一種方法來將物件的構建和表示分離,使得您可以更容易地修改和擴充套件物件的構建過程。
實作細節
以下是建立者模式的實作細節:
- 匯入必要的模組:我們需要匯入
Enum
類別和time
模組。 - 定義常數:我們定義了一些常數,例如
PizzaProgress
、PizzaDough
、PizzaSauce
、PizzaTopping
和STEP_DELAY
。 - 定義
Pizza
類別:我們定義了一個Pizza
類別,代表了一個披薩物件。 - 定義建立者類別:我們定義了兩個建立者類別,
MargaritaBuilder
和CreamyBaconBuilder
,這些類別負責構建不同的披薩型別。 - 定義
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)和微服務架構中將扮演更重要的角色。隨著系統複雜度的提升,物件的建立邏輯也將更加複雜。建造者模式可以幫助我們更好地管理這種複雜性,提高程式碼的可讀性和可維護性。同時,結合函式式程式設計的思想,建造者模式可以進一步提升物件建立的效率和靈活性。
對於追求程式碼品質和可維護性的開發團隊,深入理解並應用建造者模式將是提升軟體設計水平的關鍵一步。建議開發團隊在設計複雜物件的建立流程時,優先考慮使用建造者模式,並根據實際情況選擇合適的變體和最佳實踐,以最大程度地發揮其優勢。