文本是《设计模式(共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中都有很好的体现:
- 简单工厂:通过一个工厂类根据参数创建不同的产品实例
- 工厂方法:将对象创建延迟到子类,符合开闭原则
- 抽象工厂:创建相关产品族,确保产品之间的一致性
Python的动态特性使得工厂模式的实现更加灵活,可以利用反射、动态导入等特性来增强扩展性。