Python 设计模式之抽象工厂模式

文章目录

抽象工厂模式属于创建型设计模式,一般用来创建复杂的对象,这种对象由许多小对象组成,这些小对象都属于某个特定的类别。


从一个例子谈起

常见的例子是在家具商城中,有家具产品:椅子和沙发等等;这些产品同时有中式、日式等风格。如果用户期望一批日式风格的家具,你就得给它一批日式风格的家具。这里中式风格的家具生产厂就是一个复杂对象,而具体的中式椅子就是小对象。

假设现在客户端代码希望通过调用代码,生产出一批家具,这批家具必须风格一致。没有使用这种设计模式前,我们可能会这样实现代码。

python 复制代码
class ChinaSofa:
    @classmethod
    def create_sofa(cls):
        return ChinaSofa()

    def __str__(self):
        return "china style sofa"

class ChinaChair:
    @classmethod
    def create_chair(cls):
        return ChinaChair()

    def __str__(self):
        return "china style chair"

class JapanSofa:
    @classmethod
    def create_sofa(cls):
        return JapanSofa()

    def __str__(self):
        return "japan style sofa"

class JapanChair:
    @classmethod
    def create_chair(cls):
        return JapanChair()

    def __str__(self):
        return "japan style chair"


def main():
     print(ChinaSofa.create_sofa())
     print(ChinaChair.create_chair())

main()

这里 main 函数可以理解为客户端代码,我们看到在生产某种风格的产品时,代码需要知道用 ChinaSofa 类和 ChinaChair

python 复制代码
print(ChinaSofa.create_sofa())
print(ChinaChair.create_chair())

这里有两个明显的缺点:

  1. 如果在产品非常多的情况下,使用者可能会在代码中混入其他风格的类来生成产品。这意味着需要使用者很大的心智负担
  2. 如果现在增加一种欧式风格的沙发和椅子,我们就需要修改 main 函数的代码,即代码间存在耦合

作为客户端代码的开发者会更希望自己不需要关注生产中式风格的椅子用哪个类、日式风格的椅子又是哪个类。对他来说理想的行为应该是:
client factory 未来都制作中式风格的家具给我 我要把椅子 制作中式风格的椅子 我要张沙发 制作中式风格的沙发 client factory

基于这样的设想,可以预见我们的main 函数将是这样的:

python 复制代码
def main():
	# 风格的选择可以作为配置文件或者函数参数传入
    factory=ChinaStyle() 
    print(factory.create_sofa())
    print(factory.create_chair())

在这种调用形式下,我们解决了上面提到的两个缺点,那么该如何实现呢?

抽象工厂模式的组件构成

在进入实现之前,需要了解下抽象工厂模式由哪些组件组成:

  1. 抽象工厂

    抽象工厂是一个高层次的蓝图,它定义了创建相关对象族的一系列规则,而无需指定具体的类。它声明了一系列方法,每个方法负责创建一种特定类型的对象,并确保具体工厂遵循一个通用接口,从而提供一种一致的方式来生成相关的对象集。

  2. 具体的工厂

    具体工厂实现抽象工厂定义的接口函数。它包含在一个系列中创建特定对象实例的逻辑。一般会存在多个具体工厂,每个工厂都是为生产一个不同的相关对象系列而量身定制的。

  3. 抽象的产品

    抽象产品通过定义一组通用方法或属性来表示相关对象的系列。它是一个系列中所有具体产品都必须遵守的抽象或接口类型,并为具体产品的互换使用提供了统一的方式。

  4. 具体的产品

    它们是由具体工厂创建的对象的实际实例。它们实现抽象产品中声明的方法,确保族内的一致性,并属于相关对象的特定类别或族。

  5. 客户端

    客户利用抽象工厂创建对象系列,无需指定具体类型,并通过抽象产品提供的抽象接口与对象交互。客户可通过更改具体工厂实例,灵活地在对象系列之间无缝切换。

具体的调用逻辑
抽象产品 具体产品1 class 具体产品2 class 客户端 抽象工厂 具体工厂1 具体工厂2

实际上我们可以忽略实现抽象产品

根据抽象工厂模式实现

根据上面的组件介绍,我们可以对前文的例子进行对号入座:

  1. 客户端根据期望,用特定的工厂类生成工厂实例。这些工厂类继承自一个抽象的工厂类;
  2. 抽象工厂类定义了一系列可以生成产品实例的抽象函数,因此特定的工厂类通过重写这些函数,使得他们可以生成自己系列的产品对象

根据期望的行为给出接口的关系图:

接下来就是照着这张图实现:

python 复制代码
from abc import ABC, abstractmethod

class FurnitureFactory(ABC):
    @abstractmethod
    def create_sofa(self):
        pass

    @abstractmethod
    def create_chair(self):
        pass

class ChinaStyle(FurnitureFactory):
    def create_sofa(self):
        return ChinaStyleSofa()

    def create_chair(self):
        return ChinaStyleChair()


class JapanStyle(FurnitureFactory):
    def create_sofa(self):
        return JapanStyleSofa()

    def create_chair(self):
        return JapanStyleChair()

class Sofa(ABC):
    def can_sleep():
        return "the man can sleep on it"

class ChinaStyleSofa(Sofa):
    def __str__(self):
        return "china style sofa"

class JapanStyleSofa():
    def __str__(self):
        return "japan style sofa"

class Chair(ABC):
    def can_sit():
        return "the man can sit down"

class ChinaStyleChair(Chair):
    def __str__(self):
        return "china style chair"

class JapanStyleChair(Chair):
    def __str__(self):
        return "japan style chair"

def main():
    factory = ChinaStyle()
    print(factory.create_sofa())
    print(factory.create_chair())

main()

抽象工厂模式的缺点

  • 对比这两段代码,可以发现这种设计模式下的代码更加复杂,它实现了很多的抽象工厂和抽象产品接口,而在这个简单的例子中显得有些多余。因此对于简单的系统而言,这种模式有时并不适合,它带来的代码复杂度大过了它带来的优点。
相关推荐
孤客网络科技工作室5 分钟前
Python Plotly 库使用教程
python·信息可视化·plotly
悟解了5 分钟前
《数据可视化技术》上机报告
python·信息可视化·数据分析
机器学习之心8 分钟前
时序预测 | 改进图卷积+informer时间序列预测,pytorch架构
人工智能·pytorch·python·时间序列预测·informer·改进图卷积
糊涂君-Q30 分钟前
Python小白学习教程从入门到入坑------第三十一课 迭代器(语法进阶)
python·学习·程序人生·考研·职场和发展·学习方法·改行学it
天飓35 分钟前
基于OpenCV的自制Python访客识别程序
人工智能·python·opencv
取个名字真难呐44 分钟前
矩阵乘法实现获取第i行,第j列值,矩阵大小不变
python·线性代数·矩阵·numpy
技术仔QAQ1 小时前
【tokenization分词】WordPiece, Byte-Pair Encoding(BPE), Byte-level BPE(BBPE)的原理和代码
人工智能·python·gpt·语言模型·自然语言处理·开源·nlp
WangYaolove13141 小时前
请解释Python中的装饰器是什么?如何使用它们?
linux·数据库·python
宋发元2 小时前
如何使用正则表达式验证域名
python·mysql·正则表达式
XMYX-02 小时前
Python 操作 Elasticsearch 全指南:从连接到数据查询与处理
python·elasticsearch·jenkins