当前位置:首页>文章>设计模式>设计模式:工厂模式详解(Python版)

设计模式:工厂模式详解(Python版)

文本是《设计模式(共2篇)》专题的第 2 篇。阅读本文前,建议先阅读前面的文章:

设计模式:工厂模式详解(Python版)

一、简单工厂

1️⃣ 概念

定义:由一个工厂对象决定创建出哪一种产品类的实例

类型:创建型,但不属于GOF23种设计模式

2️⃣ 适用场景

  • 工厂类负责创建的对象比较少
  • 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心

3️⃣ 优点

  • 只需要传入一个正确的参数,就可以获取你所需要的对象,而无需知道其创建细节

4️⃣ 缺点

  • 工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背了开闭原则
  • 无法形成基于继承的等级结构

5️⃣ 简单工厂Coding

① 创建Video抽象类

from abc import ABC, abstractmethod

class Video(ABC):
    @abstractmethod
    def produce(self):
        pass

② 创建实现类来实现Video类

PythonVideo

class PythonVideo(Video):
    def produce(self):
        print("录制Python课程视频")

JavaVideo

class JavaVideo(Video):
    def produce(self):
        print("录制Java课程视频")

③ 创建简单工厂类

import importlib

class VideoFactory:
    # 使用反射来提高扩展性
    def get_video(self, class_name):
        try:
            # 动态导入类
            module = importlib.import_module(__name__)
            video_class = getattr(module, class_name)
            return video_class()
        except (AttributeError, ImportError) as e:
            print(f"错误: {e}")
            return None

    # 传统方式创建对象
    def get_video_by_type(self, video_type):
        if video_type.lower() == "java":
            return JavaVideo()
        elif video_type.lower() == "python":
            return PythonVideo()
        return None

④ 编写测试类

def test():
    # 方式一:通过类型字符串创建
    # video_factory = VideoFactory()
    # video = video_factory.get_video_by_type("java")
    # if video is None:
    #     return
    # video.produce()

    # 方式二:通过类名创建
    video_factory = VideoFactory()
    video = video_factory.get_video("JavaVideo")
    if video is None:
        return
    video.produce()

if __name__ == "__main__":
    test()

6️⃣ 应用简单工厂的Python标准库示例

在Python中,datetime模块的工厂方法是一个很好的例子:

import datetime
from datetime import timezone

# 简单工厂模式的应用
def get_calendar_instance(tz=None, locale=None):
    """
    获取日历实例
    """
    if tz is None:
        tz = timezone.utc

    if locale and locale.startswith('th_TH'):
        # 返回佛教历
        return BuddhistCalendar(tz, locale)
    elif locale and locale.startswith('ja_JP'):
        # 返回日本历
        return JapaneseCalendar(tz, locale)
    else:
        # 返回公历
        return datetime.datetime.now(tz)

二、工厂方法

1️⃣ 概念

定义:定义一个创建对象的接口,但让实现接口的这个类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行

类型:创建性

2️⃣ 适用的场景

  • 创建对象需要大量重复的代码
  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  • 一个类通过其子类来指定创建哪个对象

3️⃣ 优点

  • 用户只需关心所需产品对应的工厂,无需关心创建细节
  • 加入新产品符合开闭原则,提高可扩展性

4️⃣ 缺点

  • 类的个数容易过多,增加复杂度
  • 增加了系统的抽象性和理解难度

5️⃣ 工厂方法Coding

① 创建产品类抽象类Video

from abc import ABC, abstractmethod

class Video(ABC):
    @abstractmethod
    def produce(self):
        pass

② 创建具体的产品类来实现抽象类

class FEVideo(Video):
    def produce(self):
        print("录制FE课程视频")

class JavaVideo(Video):
    def produce(self):
        print("录制Java课程视频")

class PythonVideo(Video):
    def produce(self):
        print("录制Python课程视频")

③ 创建产品抽象工厂类VideoFactory

from abc import ABC, abstractmethod

class VideoFactory(ABC):
    @abstractmethod
    def get_video(self):
        pass

④ 创建具体的产品工厂类实现产品抽象工厂

class FEVideoFactory(VideoFactory):
    def get_video(self):
        return FEVideo()

class JavaVideoFactory(VideoFactory):
    def get_video(self):
        return JavaVideo()

class PythonVideoFactory(VideoFactory):
    def get_video(self):
        return PythonVideo()

⑤ 创建测试类

def test():
    video_factory = PythonVideoFactory()
    video_factory2 = JavaVideoFactory()
    video_factory3 = FEVideoFactory()

    video = video_factory.get_video()
    video.produce()

if __name__ == "__main__":
    test()

6️⃣ 应用工厂方法的Python标准库示例

① collections.abc模块

from collections.abc import Iterable

class Collection(Iterable):
    """
    集合的抽象基类
    """
    def __len__(self):
        """返回集合中元素的数量"""
        raise NotImplementedError

    def __contains__(self, item):
        """检查集合是否包含指定元素"""
        raise NotImplementedError

    def __iter__(self):
        """返回集合的迭代器"""
        raise NotImplementedError

② List实现(模拟ArrayList)

class List(Collection):
    def __init__(self):
        self.data = []

    def __len__(self):
        return len(self.data)

    def __contains__(self, item):
        return item in self.data

    def __iter__(self):
        return ListIterator(self.data)

    def append(self, item):
        self.data.append(item)

class ListIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        item = self.data[self.index]
        self.index += 1
        return item

三、抽象工厂

1️⃣ 概念

定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,无需指定它们具体的类

类型:创建型

2️⃣ 适用场景

  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复代码
  • 提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于具体实现

3️⃣ 优点

  • 具体产品在应用层代码隔离,无须关心创建细节
  • 将一个系列的产品族统一到一起创建

4️⃣ 缺点

  • 规定了所有可能被创建的产品集合,产品族中扩展新的产品比较困难,需要修改抽象工厂的接口
  • 增加了系统的抽象性和理解难度

6️⃣ 抽象工厂Coding

① 创建抽象工厂

from abc import ABC, abstractmethod

class CourseFactory(ABC):
    @abstractmethod
    def get_video(self):
        pass

    @abstractmethod
    def get_article(self):
        pass

② 创建具体工厂来实现抽象工厂

class JavaCourseFactory(CourseFactory):
    def get_video(self):
        return JavaVideo()

    def get_article(self):
        return JavaArticle()

class PythonCourseFactory(CourseFactory):
    def get_video(self):
        return PythonVideo()

    def get_article(self):
        return PythonArticle()

③ 创建抽象产品族

from abc import ABC, abstractmethod

class Article(ABC):
    @abstractmethod
    def produce(self):
        pass

class Video(ABC):
    @abstractmethod
    def produce(self):
        pass

④ 创建具体产品

class JavaArticle(Article):
    def produce(self):
        print("编写Java课程手记")

class JavaVideo(Video):
    def produce(self):
        print("录制Java课程视频")

class PythonArticle(Article):
    def produce(self):
        print("编写Python课程手记")

class PythonVideo(Video):
    def produce(self):
        print("录制Python课程视频")

⑤ 创建测试类

def test():
    course_factory = JavaCourseFactory()
    video = course_factory.get_video()
    article = course_factory.get_article()
    video.produce()
    article.produce()

if __name__ == "__main__":
    test()

7️⃣ 抽象工厂的应用

① 模拟SQLAlchemy的会话工厂

from abc import ABC, abstractmethod

class SessionFactory(ABC):
    @abstractmethod
    def open_session(self):
        pass

    @abstractmethod
    def open_session_with_autocommit(self, auto_commit=True):
        pass

    @abstractmethod
    def open_session_with_connection(self, connection):
        pass

    @abstractmethod
    def open_session_with_isolation_level(self, level):
        pass

    def get_configuration(self):
        pass

② 具体会话工厂实现

class DefaultSessionFactory(SessionFactory):
    def open_session_with_isolation_level(self, level, auto_commit=False):
        return self._open_session_from_datasource(level, auto_commit)

    def _open_session_from_datasource(self, level, auto_commit):
        try:
            environment = self.configuration.get_environment()
            transaction_factory = self._get_transaction_factory_from_environment(environment)
            tx = transaction_factory.new_transaction(
                environment.get_datasource(), level, auto_commit
            )
            executor = self.configuration.new_executor(tx)
            return DefaultSession(self.configuration, executor, auto_commit)
        except Exception as e:
            if 'tx' in locals():
                self._close_transaction(tx)
            raise Exception(f"Error opening session. Cause: {e}")

    def open_session(self):
        # 默认实现
        pass

    def open_session_with_autocommit(self, auto_commit=True):
        # 自动提交实现
        pass

    def open_session_with_connection(self, connection):
        # 使用连接实现
        pass

总结

工厂模式的三种形式在Python中都有很好的体现:

  1. 简单工厂:通过一个工厂类根据参数创建不同的产品实例
  2. 工厂方法:将对象创建延迟到子类,符合开闭原则
  3. 抽象工厂:创建相关产品族,确保产品之间的一致性

Python的动态特性使得工厂模式的实现更加灵活,可以利用反射、动态导入等特性来增强扩展性。

设计模式

设计模式的分类与七大原则详解 | 创建型、结构型、行为型模式

2025-8-28 12:11:38

工具配置

探索前沿AI对话:LibreChat部署的深度洞察与最佳实践

2025-7-30 11:45:15

搜索