设计模式——简单工厂
概述
简单工厂(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()
Comments NOTHING