建造者模式能有效分離物件的建構與表示,尤其適用於複雜物件的組裝。它將物件的建立步驟分解成多個方法,讓使用者能逐步設定物件屬性,最終透過建構方法取得完整物件。原型模式則提供一種物件複製機制,透過深度複製現有物件,快速產生新的相似物件,避免重複建構流程,提升程式碼效率。兩種模式都能提升程式碼的彈性與可維護性,適用於不同場景。

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 中,這幾乎是自然的,因為我們有一個副本功能可以很好地幫助使用這種技術。

實作原型模式的步驟

  1. 定義一個基礎類別,包含一個 clone() 方法。
  2. 建立一個具體類,繼承基礎類別,並實作 clone() 方法。
  3. 使用 deepcopy() 函式從具體類建立一個副本。

實作原型模式的優點

  • 可以建立複雜物件的副本而不需要從頭開始建立。
  • 可以節省時間和資源。

實作原型模式的缺點

  • 建立副本可能會很耗費資源。
  • 如果物件之間有相互依賴, 建立副本可能會很複雜。

實作單例模式

單例模式是一種建立模式,保證一個類只有一個例項,並提供一個全域性點存取該例項。

實作單例模式的步驟

  1. 定義一個類,包含一個私有建構方法。
  2. 建立一個靜態方法,傳回類的例項。
  3. 確保類的例項只被建立一次。

實作單例模式的優點

  • 可以保證一個類只有一個例項。
  • 可以提供一個全域性點存取該例項。

實作單例模式的缺點

  • 可能會導致程式碼耦合度增加。
  • 可能會導致測試困難。
程式碼示例
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__ 方法將接受必要的引數,包括 namedomaindescriptionauthor,這些引數將被設定為對應的例項變數。此外,為了增加靈活性,我們還會使用 **kwargs 讓使用者可以傳遞額外的關鍵字引數,以便設定其他任意屬性。

屬性設定

使用 Python 的 setattr 函式,可以動態設定物件的屬性。這個函式的語法是 setattr(obj, attr, val),它可以設定物件 obj 的屬性 attrval。我們將使用這個技巧來設定 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 物件,並設定其基本屬性和額外的選擇性屬性。

實作原型模式

在物件導向設計中,原型模式是一種重要的設計模式,允許我們建立新的物件例項,同時根據現有的物件例項進行複製。以下是如何實作原型模式的步驟和相關程式碼:

原型模式的核心思想

原型模式的核心思想是建立一個新的物件例項,同時根據現有的物件例項進行複製。這樣可以避免建立多個相同的物件例項,同時也可以節省系統資源。

實作原型模式的步驟

  1. 定義一個原型類(Prototype),這個類需要實作一個克隆(clone)方法,該方法用於建立新的物件例項。
  2. 在原型類中,使用 copy.deepcopy() 函式進行物件的深度複製。
  3. 建立一個新的物件例項,同時根據現有的物件例項進行複製。

原型模式的程式碼實作

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設定新物件的nameurl屬性:

for key in attrs:
    setattr(obj, key, attrs[key])

這樣,我們就可以動態設定新物件的屬性,無需手動編寫程式碼。

原型模式(Prototype Pattern)實作

原型模式是一種建立型設計模式,允許我們複製現有的物件,而不需要知道它們的類別。這種模式尤其在複製複雜物件時非常有用,因為它可以節省建立新物件的時間和資源。

原型模式的實作步驟

  1. 定義原型類別:首先,我們需要定義一個原型類別(Prototype),這個類別應該包含一個 clone() 方法,該方法傳回一個與原型物件相同的新物件。
  2. 實作原型類別:然後,我們需要實作原型類別,為其新增必要的屬性和方法。
  3. 建立原型物件:接下來,我們建立一個原型物件,這個物件將作為我們複製的基礎。
  4. 註冊原型物件:我們需要有一種方式來管理和儲存原型物件,以便我們可以根據需要複製它們。這通常是透過一個原型管理器(Prototype Manager)來完成的。
  5. 複製原型物件:當我們需要建立一個新的物件時,我們可以從原型管理器中取得原型物件,並使用其 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()

結果分析

當我們執行這個程式時,我們會看到 site1site2 的內容和記憶體地址。由於 site2 是透過 clone() 方法建立的,因此它的內容與 site1 相同,但記憶體地址不同。

這證明瞭原型模式的實作是正確的,我們可以使用 clone() 方法建立新的物件,而不需要知道它們的類別。這種模式在需要複製複雜物件時尤其有用,因為它可以節省建立新物件的時間和資源。

從系統資源消耗與處理效率的綜合考量來看,建造者模式在建立複雜物件時展現出顯著的優勢。透過逐步構建,它有效避免了繁瑣的建構函式和大量的引數傳遞,從而簡化了物件建立的流程並提升了程式碼的可讀性。此外,建造者模式的靈活性也值得關注,它允許根據不同需求定製物件的構建過程,無需修改既有程式碼即可支援新的物件屬性或組態,降低了程式碼的耦合度。然而,對於簡單物件而言,建造者模式的優勢並不明顯,反而可能增加程式碼的複雜度。因此,在實務應用中,技術團隊應根據物件的複雜程度和專案的實際需求,謹慎評估建造者模式的適用性,並權衡其帶來的效益與成本。對於追求程式碼簡潔性和可維護性的專案,優先考慮將建造者模式應用於複雜物件的建立,方能最大程度地發揮其優勢。未來,隨著物件導向程式設計的持續發展,預計建造者模式將與其他建立型模式更緊密地結合,衍生出更具彈性且功能更強大的物件建立方案。