前言
GOF设计模式分三大类:
- 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
- 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
- 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
一、抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)
-
定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。即将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产。
-
解决问题:如何设计一个能够创建一系列产品对象的工厂?(每一个具体工厂可以生产属于一个产品族的所有产品)
-
使用场景:
- 与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,而是负责创建一族产品。
-
相关术语:
- 产品等级结构:产品等级结构即产品的继承结构,例如一个抽象类是电视机,其子类有A品牌电视机、B品牌电视机、C品牌电视机等等
- 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。例如X工厂生产的电视机、电冰箱、空调等等
-
优点:
- 与工厂方法模式相比,减少了系统中类的个数。能够保证客户端始终只使用同一个产品族中的对象。
- 对于增加新的产品族,抽象工厂模式很好地支持了开闭原则。
-
缺点:
- 对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了开闭原则。
二、抽象工厂模式示例
使用抽象工厂模式来设计界面皮肤库,一种是绿色风格界面,一种是蓝色风格界面
# 模块 skins.py
"""抽象产品簇"""
class Button:
"""抽象产品按钮"""
def display(self):
raise NotImplementedError
class TextField:
"""抽象产品文本框"""
def display(self):
raise NotImplementedError
class ComboBox:
"""抽象产品组合框"""
def display(self):
raise NotImplementedError
"""具体产品簇Spring"""
class SpringButton(Button):
def display(self):
print("显示绿色按钮")
class SpringTextField(TextField):
def display(self):
print("显示绿色文本框")
class SpringComboBox(ComboBox):
def display(self):
print("显示绿色组合框")
"""具体产品簇Summer"""
class SummerButton(Button):
def display(self):
print("显示蓝色按钮")
class SummerTextField(TextField):
def display(self):
print("显示蓝色文本框")
class SummerComboBox(ComboBox):
def display(self):
print("显示蓝色组合框")
"""抽象工厂"""
class SkinFactory:
def create_button(self) -> Button:
raise NotImplementedError
def create_text_field(self) -> TextField:
raise NotImplementedError
def create_combo_box(self) -> ComboBox:
raise NotImplementedError
"""具体工厂"""
class SpringSkinFactory(SkinFactory):
def create_button(self):
return SpringButton()
def create_text_field(self):
return SpringTextField()
def create_combo_box(self):
return SpringComboBox()
class SummerSkinFactory(SkinFactory):
def create_button(self):
return SummerButton()
def create_text_field(self):
return SummerTextField()
def create_combo_box(self):
return SummerComboBox()
引入配置文件config.json
{
"class_name": "SummerSkinFactory"
}
通过工具类JsonUtil读取配置文件
# 模块 utils.py
from pathlib import Path
import json
class JsonUtil:
@staticmethod
def get_value(key: str):
path = Path("config.json")
contents = path.read_text(encoding="utf-8")
conf = json.loads(contents)
return conf.get(key, None)
客户端代码
import skins
from utils import JsonUtil
class_name = JsonUtil.get_value("class_name")
klass = getattr(skins, class_name, None)
if klass:
factory: skins.SkinFactory = klass()
bt = factory.create_button()
tf = factory.create_text_field()
cb = factory.create_combo_box()
bt.display()
tf.display()
cb.display()
### 输出结果
显示蓝色按钮
显示蓝色文本框
显示蓝色组合框
三、抽象工厂模式在Django框架中的应用
Django 的数据库后端系统允许你使用不同的数据库系统(如 PostgreSQL、MySQL、SQLite 等),并且可以很容易地在它们之间切换,而不需要改变你的模型代码。
# Django项目的配置文件 settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
Django 的数据库后端系统定义了一个抽象的接口,不同的数据库引擎(如 django.db.backends.postgresql
, django.db.backends.mysql
, django.db.backends.sqlite3
等)实现了这个接口。这些数据库引擎就是具体工厂,它们根据数据库的类型创建对应的数据库连接和操作对象。
# 抽象工厂 django.db.backends.base.base
class BaseDatabaseWrapper:
"""Represent a database connection."""
# ...
# 具体工厂 django.db.backends.mysql.base
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = "mysql"
# ...
# 具体工厂 django.db.backends.postgresql.base
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = "postgresql"
# ...
# 具体工厂 django.db.backends.sqlite3.base
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = "sqlite"
# ...
您正在阅读的是《设计模式Python版》专栏!关注不迷路~