[Python-設(shè)計(jì)模式] 創(chuàng)建型模式- 工廠方法模式

創(chuàng)建型模式

創(chuàng)建型模式提供了創(chuàng)建對(duì)象的機(jī)制, 能夠提升已有代碼的靈活性和可復(fù)用性。

工廠方法模式

工廠方法模式是一種創(chuàng)建型設(shè)計(jì)模式, 其在父類中提供一個(gè)創(chuàng)建對(duì)象的方法, 允許子類決定實(shí)例化對(duì)象的類型。

工廠方法模式結(jié)構(gòu)

產(chǎn)品 (Prod-uct) 將會(huì)對(duì)接口進(jìn)行聲明。 對(duì)于所有由創(chuàng)建者及其子類構(gòu)建的對(duì)象, 這些接口都是通用的。

具體產(chǎn)品 (Con-crete Prod-ucts) 是產(chǎn)品接口的不同實(shí)現(xiàn)。

具體創(chuàng)建者 (Con-crete Cre-ators) 將會(huì)重寫基礎(chǔ)工廠方法, 使其返回不同類型的產(chǎn)品。

注意, 并不一定每次調(diào)用工廠方法都會(huì)創(chuàng)建新的實(shí)例。 工廠方法也可以返回緩存、 對(duì)象池或其他來源的已有對(duì)象。

創(chuàng)建者 (Cre-ator) 類聲明返回產(chǎn)品對(duì)象的工廠方法。 該方法的返回對(duì)象類型必須與產(chǎn)品接口相匹配。

你可以將工廠方法聲明為抽象方法, 強(qiáng)制要求每個(gè)子類以不同方式實(shí)現(xiàn)該方法。 或者, 你也可以在基礎(chǔ)工廠方法中返回默認(rèn)產(chǎn)品類型。

注意, 盡管它的名字是創(chuàng)建者, 但它最主要的職責(zé)并不是創(chuàng)建產(chǎn)品。 一般來說, 創(chuàng)建者類包含一些與產(chǎn)品相關(guān)的核心業(yè)務(wù)邏輯。 工廠方法將這些邏輯處理從具體產(chǎn)品類中分離出來。 打個(gè)比方, 大型軟件開發(fā)公司擁有程序員培訓(xùn)部門。 但是, 這些公司的主要工作還是編寫代碼, 而非生產(chǎn)程序員。

實(shí)現(xiàn)方式

1,讓所有產(chǎn)品都遵循同一接口。 該接口必須聲明對(duì)所有產(chǎn)品都有意義的方法。
2,在創(chuàng)建類中添加一個(gè)空的工廠方法。 該方法的返回類型必須遵循通用的產(chǎn)品接口。

3,在創(chuàng)建者代碼中找到對(duì)于產(chǎn)品構(gòu)造函數(shù)的所有引用。 將它們依次替換為對(duì)于工廠方法的調(diào)用, 同時(shí)將創(chuàng)建產(chǎn)品的代碼移入工廠方法。

4,你可能需要在工廠方法中添加臨時(shí)參數(shù)來控制返回的產(chǎn)品類型。

5,工廠方法的代碼看上去可能非常糟糕。 其中可能會(huì)有復(fù)雜的 switch分支運(yùn)算符, 用于選擇各種需要實(shí)例化的產(chǎn)品類。 但是不要擔(dān)心, 我們很快就會(huì)修復(fù)這個(gè)問題。

6,現(xiàn)在, 為工廠方法中的每種產(chǎn)品編寫一個(gè)創(chuàng)建者子類, 然后在子類中重寫工廠方法, 并將基本方法中的相關(guān)創(chuàng)建代碼移動(dòng)到工廠方法中。

7,如果應(yīng)用中的產(chǎn)品類型太多, 那么為每個(gè)產(chǎn)品創(chuàng)建子類并無太大必要, 這時(shí)你也可以在子類中復(fù)用基類中的控制參數(shù)。

8,如果代碼經(jīng)過上述移動(dòng)后, 基礎(chǔ)工廠方法中已經(jīng)沒有任何代碼, 你可以將其轉(zhuǎn)變?yōu)槌橄箢悺?如果基礎(chǔ)工廠方法中還有其他語句, 你可以將其設(shè)置為該方法的默認(rèn)行為。

工廠方法模式優(yōu)缺點(diǎn)

√ 你可以避免創(chuàng)建者和具體產(chǎn)品之間的緊密耦合。

√ 單一職責(zé)原則。 你可以將產(chǎn)品創(chuàng)建代碼放在程序的單一位置, 從而使得代碼更容易維護(hù)。
√ 開閉原則。 無需更改現(xiàn)有客戶端代碼, 你就可以在程序中引入新的產(chǎn)品類型。

× 應(yīng)用工廠方法模式需要引入許多新的子類, 代碼可能會(huì)因此變得更復(fù)雜。 最好的情況是將該模式引入創(chuàng)建者類的現(xiàn)有層次結(jié)構(gòu)中。

main.py: 概念示例


from __future__ import annotations
from abc import ABC, abstractmethod


class Creator(ABC):
    """
    The Creator class declares the factory method that is supposed to return an
    object of a Product class. The Creator's subclasses usually provide the
    implementation of this method.
    """

    @abstractmethod
    def factory_method(self):
        """
        Note that the Creator may also provide some default implementation of
        the factory method.
        """
        pass

    def some_operation(self) -> str:
        """
        Also note that, despite its name, the Creator's primary responsibility
        is not creating products. Usually, it contains some core business logic
        that relies on Product objects, returned by the factory method.
        Subclasses can indirectly change that business logic by overriding the
        factory method and returning a different type of product from it.
        """

        # Call the factory method to create a Product object.
        product = self.factory_method()

        # Now, use the product.
        result = f"Creator: The same creator's code has just worked with {product.operation()}"

        return result


"""
Concrete Creators override the factory method in order to change the resulting
product's type.
"""


class ConcreteCreator1(Creator):
    """
    Note that the signature of the method still uses the abstract product type,
    even though the concrete product is actually returned from the method. This
    way the Creator can stay independent of concrete product classes.
    """

    def factory_method(self) -> Product:
        return ConcreteProduct1()


class ConcreteCreator2(Creator):
    def factory_method(self) -> Product:
        return ConcreteProduct2()


class Product(ABC):
    """
    The Product interface declares the operations that all concrete products
    must implement.
    """

    @abstractmethod
    def operation(self) -> str:
        pass


"""
Concrete Products provide various implementations of the Product interface.
"""


class ConcreteProduct1(Product):
    def operation(self) -> str:
        return "{Result of the ConcreteProduct1}"


class ConcreteProduct2(Product):
    def operation(self) -> str:
        return "{Result of the ConcreteProduct2}"


def client_code(creator: Creator) -> None:
    """
    The client code works with an instance of a concrete creator, albeit through
    its base interface. As long as the client keeps working with the creator via
    the base interface, you can pass it any creator's subclass.
    """

    print(f"Client: I'm not aware of the creator's class, but it still works.\n"
          f"{creator.some_operation()}", end="")


if __name__ == "__main__":
    print("App: Launched with the ConcreteCreator1.")
    client_code(ConcreteCreator1())
    print("\n")

    print("App: Launched with the ConcreteCreator2.")
    client_code(ConcreteCreator2())

輸出結(jié)果:
App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct1}

App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容