设计模式——简单工厂

概述

简单工厂(Simple Factory Pattern)模式是一种创建型设计模式,在它提供了创建对象过程和使用对象过程分离的能力,具体来说,其在父类中提供创建对象方法,并且在子类中完成实例化对象的类型。事实上,简单工厂模式并不是正式的设计模式,也有人将其称之为一种编程习惯。但无可非议的是,简单工厂是工厂模式的基础,它使用一个单独的工厂类创建不同的对象,并依据传入的参数决定创建那种类型的对象。

简单工厂适用于生成复杂对象的场景,如果生成对象较为简单,通过new即可完成创建,不必使用工厂模式。当使用工厂模式时,势必需要引入一个工厂类,系统总体复杂度增加。

简单工厂模式结构

在简单工厂中,通常包含以下角色:

  • 抽象产品(Product):定义产品的规范,描述产品的主要特性和功能。产品会对接口进行声明。对于所有由创建者及其子类结构的对象,抽象产品接口都是通用的。
  • 具体产品(Concrete Products):实现或者继承抽象产品的子类,是对产品接口的不同实现
  • 创建者(Creator):声明返回产品对象的工厂方法。该方法返回的对象类型必须和产品接口相匹配。
  • 具体工厂(Concrete Creator):提供创建产品的方法,调用者通过该方法来获取产品。完成对基础工厂方法的重写,使其返回不同类型的产品。

简单工厂的优缺点

优点
  • 调用者只需要知道对象的名称就可以顺利创建对象,避免了创建者和具体产品之间的紧密耦合
  • 符合开闭原则,拓展性能高,当需要增加新的产品时,可以通过拓展一个工厂类就可以实现
  • 屏蔽了产品实现的具体细节,调用者通过调用产品的接口即可实现相关功能
  • 符合单一职责原则,可以将产品创建代码放在程序的单一位置,使得代码更加容易维护
缺点
  • 当产品增加时,必须增加具体的嘞和对应的工厂,造成系统中类的数量成倍增加,系统的复杂度和具体类的依赖同步加大。

简单工厂模式的适用场景

  • 在编写代码过程中,如果无法预知对象确切类别及其依赖关系时,可以使用工厂方法。

    例如,当需要在应用中添加某个新产品时,只需要开发新的创建者子类,然后重写其工厂方法即可

  • 如果希望其他人可以拓展软件或框架的内部组件,可以使用工厂方法

    例如,假设标准库中只有矩形,若希望绘制原型,则可以使用RoundShape子类继承Shape类,并重写createShape方法,使其返回的对象为RoundShape。这样就实现了矩形和圆形的快速替代。

  • 如果希望复用现有对象而不是每次创建新对象以节省系统资源,可以使用简单工厂方法

    在处理大型资源密集型对象(比如数据库连、文件系统和网络资源等),需要一个既能够创建新对象,又可以复用现有对象的普通方法,显然简单工厂模式非常适用于这一场景。

实现方式

  • 让所有产品都遵循同一接口,该接口必须声明对所有产品都有意义的方法
  • 在创建类中添加一个空的工厂方法。该方法的返回类型遵循通用的产品接口
  • 在创建者代码中找到对于产品构造函数的所有引用,将他们依次替换为对于工厂方法的调用,同时将创建产品的代码移植进入工厂方法。
  • 为工厂方法的每个产品创建一个子类,然后在子类中重写工厂方法,将基本方法中的相关创建代码移动到工厂方法中

应用场景

  • 日志记录:日志可能记录到本地硬盘、系统事件、远程服务器等
  • 数据库访问:当用户不知道系统最终使用哪种数据库,或使用的数据库可能发生变化时
  • 连接服务器的框架设计:需要支持“POP3"、"IMAP"、"HTTP"三种协议,可以将这三种协议作为产品类,共同实现一个接口。

与其他设计模式的关系

  • 许多设计工作的初期都会采用简单工厂(较为简单,可以方便的通过子类进行定制),随后演化为使用抽象工厂模式、原型模式和生成器模式(更灵活但是更复杂)
  • 抽象工厂模式通常基于一组简单工厂方法,同时也可以使用原型模式来生成这些类的方法。
  • 可以同时使用简单工厂和迭代器模式,让子类集合返回不同类型的迭代器
  • 原型并不基于继承,没有继承的缺点,但是需要对被复制对象进行复杂的初始化。简单工厂基于继承,但是其不需要进行初始化步

代码框架

from __future__ import annotations
from abc import ABC,abstractmethod

class Creator(ABC):
    @abstractmethod
    def factory_method(self):
        pass

    def some_operation(self):
        product = self.factory_method()
        result = f"Creator: The same creator's code has just worked with {product.operation()}"
        return result

class ConcreteCreator1(Creator):
    def factory_method(self):
        return ConcreteProduct1()

class ConcreteCreator2(Creator):
    def factory_method(self) -> Product:
        return ConcreteProduct2()

class Product(ABC):
    def operation(self):
        pass

class ConcreteProduct1(Product):
    def operation(self) -> str:
        return "{Result of the ConcreteProduct1}"

class ConcreteProduct2(Product):
    def operation(self) -> str:
        return "{Result of the ConcreteProduct2}"

def client_code(creator):
    print(f"Client: I'm not aware of the creator's class, but it still works.\n"
          f"{creator.some_operation()}", end="")

if __name__ == "__main__":
    print("App: Launched with the ConcreteCreator1.")
    client_code(ConcreteCreator1())
    print("\n")

    print("App: Launched with the ConcreteCreator2.")
    client_code(ConcreteCreator2())

代码示例

# 抽象产品
class BaseOperate:

    def __init__(self):
        self.result = 0

    def get_result(self):
        return self.result

# 具体产品
class OperationAdd(BaseOperate):
    def __init__(self, num1, num2):
        self.result = num1 + num2

    def get_result(self):
        return self.result

class OperationDiv(BaseOperate):
    def __init__(self, num1, num2):
        self.result = num1 / num2

    def get_result(self):
        return self.result

class OperationSub(BaseOperate):
    def __init__(self, num1, num2):
        self.result = num1 - num2

    def get_result(self):
        return self.result

class OperationMult(BaseOperate):
    def __init__(self, num1, num2):
        self.result = num1 * num2

    def get_result(self):
        return self.result

# 简单工厂
class OperationFactory:
    @staticmethod
    def createOperate(operate, num1, num2):
        optdict = {
            '+': OperationAdd,
            '-': OperationSub,
            '*': OperationMult,
            '/': OperationSub
        }
        oper = BaseOperate()
        if (operate in optdict):
            oper = optdict[operate](num1, num2)
        return oper

# 创建者
def clientUI():
    opt = input("please input a operation")
    num1 = int(input("please input a number"))
    num2 = int(input("please input a number"))
    oper = OperationFactory.createOperate(opt, num1, num2)
    print(oper.get_result())
    return

if __name__ == '__main__':
    clientUI()

参考链接

  1. https://m.runoob.com/design-pattern/factory-pattern.html
  2. https://refactoringguru.cn/design-patterns/factory-method/python/example
  3. https://blog.csdn.net/m0_62410482/article/details/129989726
  4. https://zhuanlan.zhihu.com/p/671426189
  • alipay_img
  • wechat_img
Talk is cheap, show me the code.
最后更新于 2024-09-15