建造者模式能有效分離物件的建構與表示,尤其適用於複雜物件的組裝。它將物件的建立步驟分解成多個方法,讓使用者能逐步設定物件屬性,最終透過建構方法取得完整物件。原型模式則提供一種物件複製機制,透過深度複製現有物件,快速產生新的相似物件,避免重複建構流程,提升程式碼效率。兩種模式都能提升程式碼的彈性與可維護性,適用於不同場景。
import copy
class Website:
def __init__(self, name, description, author, category, keywords):
self.name = name
self.description = description
self.author = author
self.category = category
self.keywords = keywords
def __str__(self):
return f'Website: {self.name}, Description: {self.description}, Author: {self.author}, Category: {self.category}, Keywords: {self.keywords}'
def clone(self, **attrs):
clone = copy.deepcopy(self)
clone.__dict__.update(attrs)
return clone
class Prototype:
def __init__(self):
self._objects = {}
def register(self, identifier, obj):
self._objects[identifier] = obj
def unregister(self, identifier):
del self._objects[identifier]
def clone(self, identifier, **attrs):
obj = self._objects.get(identifier)
if obj:
return obj.clone(**attrs)
else:
raise ValueError(f'Invalid identifier: {identifier}')
class Pizza:
def __init__(self, builder):
self.garlic = builder.garlic
self.extra_cheese = builder.extra_cheese
def __str__(self):
garlic = 'yes' if self.garlic else 'no'
extra_cheese = 'yes' if self.extra_cheese else 'no'
return f'Pizza with garlic: {garlic}, extra cheese: {extra_cheese}'
class PizzaBuilder:
def __init__(self):
self.garlic = False
self.extra_cheese = False
def with_garlic(self):
self.garlic = True
return self
def with_extra_cheese(self):
self.extra_cheese = True
return self
def build(self):
return Pizza(self)
建造者模式的優點
- 分離物件的建立和表示:建造者模式允許我們將物件的建立和表示分離,使得程式碼更加模組化和易於維護。
- 提高程式碼的靈活性:建造者模式允許我們在不改變物件的表示的情況下,修改物件的建立過程。
- 減少程式碼的複雜性:建造者模式可以減少程式碼的複雜性,尤其是在需要建立複雜物件的情況下。
建造者模式的實作
以下是建造者模式的一個簡單實作:
class Pizza:
def __init__(self, builder):
self.garlic = builder.garlic
self.extra_cheese = builder.extra_cheese
def __str__(self):
garlic = 'yes' if self.garlic else 'no'
extra_cheese = 'yes' if self.extra_cheese else 'no'
return f'Pizza with garlic: {garlic}, extra cheese: {extra_cheese}'
class PizzaBuilder:
def __init__(self):
self.garlic = False
self.extra_cheese = False
def with_garlic(self):
self.garlic = True
return self
def with_extra_cheese(self):
self.extra_cheese = True
return self
def build(self):
return Pizza(self)
# 使用建造者模式建立一個 Pizza 物件
pizza_builder = PizzaBuilder()
pizza = pizza_builder.with_garlic().with_extra_cheese().build()
print(pizza)
在這個例子中,Pizza
類別代表了 Pizza 物件,PizzaBuilder
類別代表了 Pizza 建造者。建造者模式允許我們在不改變 Pizza 物件的表示的情況下,修改 Pizza 物件的建立過程。
流暢建造者模式
流暢建造者模式是一種變化的建造者模式,允許我們將建造者方法的呼叫連結起來。這種模式可以使得程式碼更加簡潔和易於閱讀。
class Pizza:
def __init__(self, builder):
self.garlic = builder.garlic
self.extra_cheese = builder.extra_cheese
def __str__(self):
garlic = 'yes' if self.garlic else 'no'
extra_cheese = 'yes' if self.extra_cheese else 'no'
return f'Pizza with garlic: {garlic}, extra cheese: {extra_cheese}'
class PizzaBuilder:
def __init__(self):
self.garlic = False
self.extra_cheese = False
def with_garlic(self):
self.garlic = True
return self
def with_extra_cheese(self):
self.extra_cheese = True
return self
def build(self):
return Pizza(self)
# 使用流暢建造者模式建立一個 Pizza 物件
pizza = (PizzaBuilder()
.with_garlic()
.with_extra_cheese()
.build())
print(pizza)
在這個例子中,建造者方法的呼叫被連結起來,使得程式碼更加簡潔和易於閱讀。
建構者模式(Builder Pattern)概述
建構者模式是一種設計模式,主要用於建立複雜物件的過程中。它允許使用者透過一步一步的方式來建立物件,並且可以根據不同的需求來建立不同的物件。
建構者模式的優點
- 建構者模式可以用於建立複雜物件,尤其是當物件的建立過程涉及多個步驟時。
- 建構者模式可以提供更好的控制和靈活性,允許使用者根據不同的需求來建立不同的物件。
- 建構者模式可以減少物件建立過程中的錯誤和複雜性。
建構者模式的應用場景
- 建構者模式常用於建立複雜物件,例如:汽車、電腦等。
- 建構者模式也可以用於建立不同版本的物件,例如:不同組態的電腦。
- 建構者模式還可以用於建立物件的不同表示形式,例如:圖片、檔案等。
建構者模式的實作
以下是一個簡單的建構者模式實作例子:
class Pizza:
def __init__(self, builder):
self.garlic = builder.garlic
self.extra_cheese = builder.extra_cheese
def __str__(self):
cheese = 'yes' if self.extra_cheese else 'no'
info = (f'Garlic: {self.garlic}', f'Extra cheese: {cheese}')
return '\n'.join(info)
class PizzaBuilder:
def __init__(self):
self.garlic = False
self.extra_cheese = False
def add_garlic(self):
self.garlic = True
return self
def add_extra_cheese(self):
self.extra_cheese = True
return self
def build(self):
return Pizza(self)
# 使用建構者模式建立一個 Pizza 物件
pizza = PizzaBuilder().add_garlic().add_extra_cheese().build()
print(pizza)
建構者模式的高階應用
建構者模式也可以用於建立複雜的物件,例如:一個具有多個屬性的物件。以下是一個簡單的例子:
class Computer:
def __init__(self, builder):
self.cpu = builder.cpu
self.memory = builder.memory
self.disk = builder.disk
def __str__(self):
info = (f'CPU: {self.cpu}', f'Memory: {self.memory}', f'Disk: {self.disk}')
return '\n'.join(info)
class ComputerBuilder:
def __init__(self):
self.cpu = None
self.memory = None
self.disk = None
def with_cpu(self, cpu):
self.cpu = cpu
return self
def with_memory(self, memory):
self.memory = memory
return self
def with_disk(self, disk):
self.disk = disk
return self
def build(self):
return Computer(self)
# 使用建構者模式建立一個 Computer 物件
computer = ComputerBuilder().with_cpu('Intel Core i7').with_memory('16GB').with_disk('1TB').build()
print(computer)
其他建立模式
在前一章中,我們涵蓋了建立模式中的第三種模式,即建造者模式,它提供了一種很好的方式來建立複雜物件的各個部分。除了工廠方法、抽象工廠和建造者模式外,還有一些其他建立模式值得討論,例如原型模式和單例模式。
實作原型模式
原型模式在需要根據現有物件使用克隆技術建立物件時很有用。正如你可能已經猜到的,想法是使用該物件的完整結構的副本來生成新物件。在 Python 中,這幾乎是自然的,因為我們有一個副本功能可以很好地幫助使用這種技術。
實作原型模式的步驟
- 定義一個基礎類別,包含一個
clone()
方法。 - 建立一個具體類,繼承基礎類別,並實作
clone()
方法。 - 使用
deepcopy()
函式從具體類建立一個副本。
實作原型模式的優點
- 可以建立複雜物件的副本而不需要從頭開始建立。
- 可以節省時間和資源。
實作原型模式的缺點
- 建立副本可能會很耗費資源。
- 如果物件之間有相互依賴, 建立副本可能會很複雜。
實作單例模式
單例模式是一種建立模式,保證一個類只有一個例項,並提供一個全域性點存取該例項。
實作單例模式的步驟
- 定義一個類,包含一個私有建構方法。
- 建立一個靜態方法,傳回類的例項。
- 確保類的例項只被建立一次。
實作單例模式的優點
- 可以保證一個類只有一個例項。
- 可以提供一個全域性點存取該例項。
實作單例模式的缺點
- 可能會導致程式碼耦合度增加。
- 可能會導致測試困難。
程式碼示例
import copy
class Prototype:
def __init__(self, name):
self.name = name
def clone(self):
return copy.deepcopy(self)
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
# 使用原型模式建立一個副本
prototype = Prototype("原型")
copy_prototype = prototype.clone()
# 使用單例模式建立一個例項
singleton = Singleton()
圖表翻譯
classDiagram Prototype <|-- Clone Prototype: +clone() Clone: +__init__() Singleton <|-- Instance Singleton: +__new__() Instance: +__init__()
網站類別的設計
在網站管理系統的核心,我們需要一個能夠儲存有用資訊的類別,例如網站名稱、網網域名稱稱、描述和作者。這個類別將被設計為 Website
,它將包含初始化方法 __init__
,用於設定網站的基本屬性。
初始化方法
__init__
方法將接受必要的引數,包括 name
、domain
、description
和 author
,這些引數將被設定為對應的例項變數。此外,為了增加靈活性,我們還會使用 **kwargs
讓使用者可以傳遞額外的關鍵字引數,以便設定其他任意屬性。
屬性設定
使用 Python 的 setattr
函式,可以動態設定物件的屬性。這個函式的語法是 setattr(obj, attr, val)
,它可以設定物件 obj
的屬性 attr
為 val
。我們將使用這個技巧來設定 Website
類別的選擇性屬性。
Website 類別定義
以下是 Website
類別的定義:
class Website:
def __init__(self, name, domain, description, author, **kwargs):
'''
網站類別的初始化方法。
:param name: 網站名稱
:param domain: 網網域名稱稱
:param description: 網站描述
:param author: 網站作者
:param kwargs: 其他選擇性屬性
'''
self.name = name
self.domain = domain
self.description = description
self.author = author
# 使用 setattr 設定選擇性屬性
for key in kwargs:
setattr(self, key, kwargs[key])
這個類別設計允許使用者建立網站物件,並設定必要的屬性,同時也提供了設定其他任意屬性的機制,增加了類別的靈活性和可擴充套件性。
範例使用
website = Website("My Website", "example.com", "This is my website", "John Doe", category="Blog", creation_date="2022-01-01")
print(website.name) # Output: My Website
print(website.domain) # Output: example.com
print(website.description) # Output: This is my website
print(website.author) # Output: John Doe
print(website.category) # Output: Blog
print(website.creation_date) # Output: 2022-01-01
這個範例展示瞭如何建立一個 Website
物件,並設定其基本屬性和額外的選擇性屬性。
實作原型模式
在物件導向設計中,原型模式是一種重要的設計模式,允許我們建立新的物件例項,同時根據現有的物件例項進行複製。以下是如何實作原型模式的步驟和相關程式碼:
原型模式的核心思想
原型模式的核心思想是建立一個新的物件例項,同時根據現有的物件例項進行複製。這樣可以避免建立多個相同的物件例項,同時也可以節省系統資源。
實作原型模式的步驟
- 定義一個原型類(Prototype),這個類需要實作一個克隆(clone)方法,該方法用於建立新的物件例項。
- 在原型類中,使用
copy.deepcopy()
函式進行物件的深度複製。 - 建立一個新的物件例項,同時根據現有的物件例項進行複製。
原型模式的程式碼實作
import copy
class Website:
def __init__(self, name, description, author, **kwargs):
self.name = name
self.description = description
self.author = author
for key, value in kwargs.items():
setattr(self, key, value)
def __str__(self):
summary = [f'Website "{self.name}"\n']
infos = vars(self).items()
ordered_infos = sorted(infos)
for attr, val in ordered_infos:
if attr == 'name':
continue
summary.append(f'{attr}: {val}\n')
return ''.join(summary)
class Prototype:
def __init__(self, name, description, author, **kwargs):
self.name = name
self.description = description
self.author = author
for key, value in kwargs.items():
setattr(self, key, value)
def clone(self):
return copy.deepcopy(self)
# 建立一個原型物件
prototype = Prototype("example", "This is an example website", "John Doe")
# 克隆原型物件
cloned_prototype = prototype.clone()
# 修改克隆的物件
cloned_prototype.name = "cloned_example"
# 列印原型物件和克隆的物件
print(prototype)
print(cloned_prototype)
結果
原型模式允許我們建立新的物件例項,同時根據現有的物件例項進行複製。這樣可以避免建立多個相同的物件例項,同時也可以節省系統資源。
內容解密:
copy.deepcopy()
函式用於進行物件的深度複製。Prototype
類實作了原型模式的核心思想,提供了一個clone()
方法用於建立新的物件例項。Website
類是一個簡單的物件類,實作了__str__()
方法用於列印物件的資訊。
圖表翻譯:
classDiagram class Prototype { +clone() } class Website { +__str__() } Prototype --|> Website
這個圖表展示了 Prototype
類和 Website
類之間的關係,Prototype
類實作了原型模式的核心思想,提供了一個 clone()
方法用於建立新的物件例項。
原型模式(Prototype)在物件複製中的應用
在物件導向程式設計中,原型模式是一種建立型模式,允許我們建立新的物件例項,方法是複製現有的物件。這種模式在需要建立多個相似物件時尤其有用。
原型模式的實作
以下是使用Python實作原型模式的例子:
import copy
class Prototype:
def __init__(self):
self.objects = {}
def register(self, identifier, obj):
self.objects[identifier] = obj
def unregister(self, identifier):
del self.objects[identifier]
def clone(self, identifier, **attrs):
found = self.objects.get(identifier)
if not found:
raise ValueError(f'Incorrect object identifier: {identifier}')
obj = copy.deepcopy(found)
for key in attrs:
setattr(obj, key, attrs[key])
return obj
class Website:
def __init__(self, name, url):
self.name = name
self.url = url
def __str__(self):
return f'Website: {self.name}, URL: {self.url}'
# 建立原型例項
prototype = Prototype()
# 建立一個Website例項
site1 = Website('Google', 'https://www.google.com')
# 將site1註冊到原型中
prototype.register('site1', site1)
# 從原型中複製site1,建立一個新的Website例項
site2 = prototype.clone('site1', name='Bing', url='https://www.bing.com')
print(site1) # Website: Google, URL: https://www.google.com
print(site2) # Website: Bing, URL: https://www.bing.com
在這個例子中,Prototype
類別負責管理物件的複製和註冊。Website
類別是被複製的物件。透過clone
方法,我們可以建立一個新的Website
例項,方法是複製現有的site1
例項,並修改其屬性。
使用setattr
設定屬性
在clone
方法中,我們使用setattr
函式設定新物件的屬性。setattr
函式的語法是setattr(obj, key, value)”,其中
obj是物件,
key是屬性的名稱,
value`是屬性的值。
例如,在clone
方法中,我們使用setattr
設定新物件的name
和url
屬性:
for key in attrs:
setattr(obj, key, attrs[key])
這樣,我們就可以動態設定新物件的屬性,無需手動編寫程式碼。
原型模式(Prototype Pattern)實作
原型模式是一種建立型設計模式,允許我們複製現有的物件,而不需要知道它們的類別。這種模式尤其在複製複雜物件時非常有用,因為它可以節省建立新物件的時間和資源。
原型模式的實作步驟
- 定義原型類別:首先,我們需要定義一個原型類別(Prototype),這個類別應該包含一個
clone()
方法,該方法傳回一個與原型物件相同的新物件。 - 實作原型類別:然後,我們需要實作原型類別,為其新增必要的屬性和方法。
- 建立原型物件:接下來,我們建立一個原型物件,這個物件將作為我們複製的基礎。
- 註冊原型物件:我們需要有一種方式來管理和儲存原型物件,以便我們可以根據需要複製它們。這通常是透過一個原型管理器(Prototype Manager)來完成的。
- 複製原型物件:當我們需要建立一個新的物件時,我們可以從原型管理器中取得原型物件,並使用其
clone()
方法建立一個新的物件。
Python 實作原型模式
以下是一個簡單的 Python 實作原型模式的例子:
import copy
class Website:
def __init__(self, name, description, author, category, keywords):
self.name = name
self.description = description
self.author = author
self.category = category
self.keywords = keywords
def __str__(self):
return f'Website: {self.name}, Description: {self.description}, Author: {self.author}, Category: {self.category}, Keywords: {self.keywords}'
def clone(self, **attrs):
# 使用 copy.deepcopy 複製物件
clone = copy.deepcopy(self)
# 更新 clone 的屬性
clone.__dict__.update(attrs)
return clone
class Prototype:
def __init__(self):
self._objects = {}
def register(self, identifier, obj):
self._objects[identifier] = obj
def unregister(self, identifier):
del self._objects[identifier]
def clone(self, identifier, **attrs):
obj = self._objects.get(identifier)
if obj:
return obj.clone(**attrs)
else:
raise ValueError(f'Invalid identifier: {identifier}')
def main():
keywords = ('python', 'data', 'apis', 'automation')
site1 = Website('ContentGardening', 'Automation and data-driven apps', 'Kamon Ayeva', 'Blog', keywords)
prototype = Prototype()
identifier = 'ka-cg-1'
prototype.register(identifier, site1)
site2 = prototype.clone(identifier, name='ContentGardeningPlayground', description='Experimentation for techniques featured on the blog', category='Membership site', creation_date='2018-08-01')
for site in (site1, site2):
print(site)
print(f'ID: {id(site)}')
if __name__ == '__main__':
main()
結果分析
當我們執行這個程式時,我們會看到 site1
和 site2
的內容和記憶體地址。由於 site2
是透過 clone()
方法建立的,因此它的內容與 site1
相同,但記憶體地址不同。
這證明瞭原型模式的實作是正確的,我們可以使用 clone()
方法建立新的物件,而不需要知道它們的類別。這種模式在需要複製複雜物件時尤其有用,因為它可以節省建立新物件的時間和資源。
從系統資源消耗與處理效率的綜合考量來看,建造者模式在建立複雜物件時展現出顯著的優勢。透過逐步構建,它有效避免了繁瑣的建構函式和大量的引數傳遞,從而簡化了物件建立的流程並提升了程式碼的可讀性。此外,建造者模式的靈活性也值得關注,它允許根據不同需求定製物件的構建過程,無需修改既有程式碼即可支援新的物件屬性或組態,降低了程式碼的耦合度。然而,對於簡單物件而言,建造者模式的優勢並不明顯,反而可能增加程式碼的複雜度。因此,在實務應用中,技術團隊應根據物件的複雜程度和專案的實際需求,謹慎評估建造者模式的適用性,並權衡其帶來的效益與成本。對於追求程式碼簡潔性和可維護性的專案,優先考慮將建造者模式應用於複雜物件的建立,方能最大程度地發揮其優勢。未來,隨著物件導向程式設計的持續發展,預計建造者模式將與其他建立型模式更緊密地結合,衍生出更具彈性且功能更強大的物件建立方案。