了解Python中的抽象工厂设计模式

102 阅读7分钟

简介

设计模式有助于使代码可理解、可扩展和可重复使用。根据所要解决的问题,有不同类别的设计模式。当代码被模块化时,在不对项目进行大幅修改的情况下,增加新的功能会更容易。

抽象工厂设计模式是一种创建模式,它提供了一个框架来创建密切相关的对象的接口,而不需要指定它们的类--因此称为"抽象"。

一个抽象类是部分实现的,它定义了它的子类应该有的要求和一些通用的子类行为,以及它们应该有的功能。具体类扩展了抽象类并提供了未实现的功能,同时继承了共同的功能。

Python中的抽象类

例如,所有的Animal都有一个eat() 函数,在所有的动物之间共同实现,但是每个动物都有独特的speak() 函数,所以抽象的Animal 类将其留给子类。

在Python中,每个抽象类都是从abc 模块的ABC 类派生出来的。抽象方法在抽象类里面声明,但不实现,所有实现的方法都传递给具体类。

在下面的例子中,注意到AbstractClass 的定义包含一个@abstractmethod 的装饰器。通过用它来装饰一个函数,我们定义所有的子类都必须有一个func() 方法的实现,因为没有默认的、通用的实现。

from abc import ABC, abstractmethod

class AbstractClass(ABC):
    @abstractmethod
    def func():
        pass

父抽象工厂类的部分实现由其子/具体类来完成。每个子类都将包含一个func() 方法来满足抽象类的要求。

在我们之前的例子基础上,我们可以这样创建一个子类。

from abc import ABC, abstractmethod

class AbstractClass(ABC):
    @abstractmethod
    def func(self):
        pass

class ChildClass(AbstractClass):
    def func(self):
        out = "This is an output"
        return out

obj = ChildClass()
print(obj.func())

Python中的抽象工厂设计模式

再来看看抽象工厂模式的定义。

通过抽象工厂模式,我们定义接口来创建相关对象的家族,而不需要指定它们的具体类。

因此,抽象工厂模式将创建对象的工作委托给另一个类。当人们希望通过抽象化实现来创建多个类别的对象时,这种模式是最适合的。

你可能对工厂这个概念很熟悉--它们是创建其他对象的对象。抽象工厂模式主要关注的是工厂对象的接口。

什么是对象家族?

一张桌子可以是圆形、方形或椭圆形的。在类似的意义上,一个普通的类,如Employee ,可能会分支出几个更具体的类。

这里有一个抽象工厂模式的可视化表示。

Visual Representation of the Abstract Factory Pattern in Python

假设你正在设计一个由两个产品组成的家族(一个浏览器和一个信使)。

  • 抽象产品。创建两个抽象类,一个用于浏览器,另一个用于信使。这些类包含抽象方法,这些方法对于产品的构建是必须的。这些抽象类被称为接口。

    在上面的例子中,网络浏览器信使是抽象产品。

  • 具体产品。具体产品继承了抽象类中的抽象方法,即抽象产品。使用接口,可以创建不同系列的产品。

    例如,在上图中,为三组不同的用户创建了三种不同的网络浏览器。如果说所有这些具体产品有一个共同点,那就是抽象类中定义的抽象方法。

  • **具体工厂(Concrete Factories)。**具体工厂按照抽象工厂的指示创建具体产品。具体工厂只能够创建那些在其中指定的产品--一个BrowserFactory 创建浏览器,而一个MessengerFactory 创建信使。另外,你可以专注于一些常见的功能,比如说--创建一个BasicFactorySecureFactory ,创建基本或安全的网络浏览器和信使实例。

    在上面提到的图表中,香草产品工厂能够创建香草的具体产品(浏览器和信使),而安全产品工厂则创建安全版本。

  • 抽象工厂。抽象工厂拥有创建抽象产品的接口,也就是说,它们包含几个返回抽象产品的方法。

    在这个例子中,具体工厂的接口被调用以获得抽象产品,如网络浏览器和信使。

实施

了解了这些术语后,让我们试着在Python中实现抽象工厂模式。

首先,我们创建抽象产品--BrowserMessenger 作为。

from abc import ABC, abstractmethod

class Browser(ABC):
    """
    Creates "Abstract Product A"
    """

    # Interface - Create Search Toolbar
    @abstractmethod
    def create_search_toolbar(self):
        pass

    # Interface - Create Browser Window
    @abstractmethod
    def create_browser_window(self):
        pass

class Messenger(ABC):
    """
    Creates "Abstract Product B"
    """

    @abstractmethod
    # Interface - Create Messenger Window
    def create_messenger_window(self):
        pass

这些类作为以下具体类的基类,即抽象产品的变体--香草和安全。

class VanillaBrowser(Browser):
    """
    Type: Concrete Product
    Abstract methods of the Browser base class are implemented.
    """

    # Interface - Create Search Toolbar
    def create_search_toolbar(self):
        print("Search Toolbar Created")

    # Interface - Create Browser Window]
    def create_browser_window(self):
        print("Browser Window Created")


class VanillaMessenger(Messenger):
    """
    Type: Concrete Product
    Abstract methods of the Messenger base class are implemented.
    """

    # Interface - Create Messenger Window
    def create_messenger_window(self):
        print("Messenger Window Created")

class SecureBrowser(Browser):
    """
    Type: Concrete Product
    Abstract methods of the Browser base class are implemented.
    """

    # Abstract Method of the Browser base class
    def create_search_toolbar(self):
        print("Secure Browser - Search Toolbar Created")

    # Abstract Method of the Browser base class
    def create_browser_window(self):
        print("Secure Browser - Browser Window Created")

    def create_incognito_mode(self):
        print("Secure Browser - Incognito Mode Created")


class SecureMessenger(Messenger):
    """
    Type: Concrete Product
    Abstract methods of the Messenger base class are implemented.
    """

    # Abstract Method of the Messenger base class
    def create_messenger_window(self):
        print("Secure Messenger - Messenger Window Created")

    def create_privacy_filter(self):
        print("Secure Messenger - Privacy Filter Created")

    def disappearing_messages(self):
        print("Secure Messenger - Disappearing Messages Feature Enabled")

你可以注意到,除了抽象方法之外,还有一些额外的功能被添加到具体产品中,使它们在自己的环境中发挥作用。

我们就快到了。现在让我们来创建抽象工厂本身和相应的具体工厂作为。

class AbstractFactory(ABC):
    """
    The Abstract Factory
    """

    @abstractmethod
    def create_browser(self):
        pass

    @abstractmethod
    def create_messenger(self):
        pass

class VanillaProductsFactory(AbstractFactory):
    """
    Type: Concrete Factory
    Implement the operations to create concrete product objects.
    """

    def create_browser(self):
        return VanillaBrowser()

    def create_messenger(self):
        return VanillaMessenger()

class SecureProductsFactory(AbstractFactory):
    """
    Type: Concrete Factory
    Implement the operations to create concrete product objects.
    """

    def create_browser(self):
        return SecureBrowser()

    def create_messenger(self):
        return SecureMessenger()

在上面的代码中,由于AbstractFactory 作为一个基类,抽象方法就像基类中提到的那样被实例化了。

让我们添加一个main() 方法,这样我们就可以看到我们的例子在运行。

def main():
    for factory in (VanillaProductsFactory(), SecureProductsFactory()):
        product_a = factory.create_browser()
        product_b = factory.create_messenger()
        product_a.create_browser_window()
        product_a.create_search_toolbar()
        product_b.create_messenger_window()

if __name__ == "__main__":
    main()

如果你想看整个代码文件,你可以在GitHub的repo中找到它。

如果我们执行我们的代码,它会返回以下输出,显示安全浏览器和安全信使的创建情况。

$ python3 abstract_factory_code.py
Browser Window Created
Search Toolbar Created
Messenger Window Created
Secure Browser - Browser Window Created
Secure Browser - Search Toolbar Created
Secure Messenger - Messenger Window Created

优点和缺点

现在我们已经实现了这个模式,让我们来权衡一下它们的优点和缺点。

优点。

  • 这种模式的主要优点是灵活性--能够为现有的产品添加更新的特性和功能,甚至可能为具体的工厂添加更新的具体产品。这可以在不破坏整个代码的情况下进行。

  • 客户端和具体产品之间的直接互动最小。在组织和压缩代码方面也有灵活性。

缺点

  • 这种模式的主要缺点是代码的可读性和可维护性。尽管它提供了一种灵活的方式来添加新的期货,但添加一个新的组件将需要添加到具体的类中,修改接口等。修改的级联效应需要开发时间。

总结

抽象工厂模式可以非常有效地用于密切相关的不同产品系列,不像工厂模式那样只能用于单一类型的产品。

抽象工厂模式解决了编写干净代码的一个主要危机。我们已经介绍了这种模式的基础知识,也通过一个例子了解了它的实现。