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()

抽象工厂模式的缺点

  • 对比这两段代码,可以发现这种设计模式下的代码更加复杂,它实现了很多的抽象工厂和抽象产品接口,而在这个简单的例子中显得有些多余。因此对于简单的系统而言,这种模式有时并不适合,它带来的代码复杂度大过了它带来的优点。
相关推荐
“AI国潮设计-小江”22 分钟前
《Python+SDXL实战:用ControlNet精准控制“英歌舞翻糖吐司”构图,附批量生成脚本》
开发语言·人工智能·python·prompt·aigc
wenwen_chao1 小时前
Python学习与开发资源合集:实用技巧与工具推荐
python
for_ever_love__2 小时前
函数——参数、lambda、*args与作用域
python·函数·大模型开发·编程基础
东莞市云毅网络有限公司2 小时前
企业资料时效性判定:Last-Modified、正文日期与版本字段三路交叉
python·sqlite·自动化运维·geo·数据监测
Query*2 小时前
深入浅出LangGraph【一】_基础篇
python·ai·langchain
XiaoMaqqqq2 小时前
市面上正规的IP驱动产业新场景新工具哪家强
运维·python·网络协议·tcp/ip
ShyanZh3 小时前
【Python3基础】19-Socket 与 TCP、UDP 编程
python·网络协议·tcp/ip·udp
惊讶的猫4 小时前
工具选对之后还不够:商城 Agent 的参数与权限治理
开发语言·python
天赐范式4 小时前
天赐范式第186天:让方差开始自洽——Bulmer效应的闭式验证
python·数字生命·天赐范式·动态运行时·遗传方差·bulmer效应
泡茶喝茶写代码4 小时前
A股量化数据工程:从 REST 接口到策略信号(第 8 篇):成长能力因子:营收与利润增速
java·python·股票数据api·股票数据api接口·股票量化数据api·股票量化数据接口·股票数据api数据