Bootstrap

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


前言

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版》专栏!关注不迷路~

;