python 抽象工厂实践+ 元类自动注册工厂类
2021-10-22 本文已影响0人
逐风细雨
抽象工厂定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
适用性
-
一个系统要独立于它的产品的创建、组合和表示时。
-
一个系统要由多个产品系列中的一个来配置时。
-
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
-
当你提供一个产品类库,而只想显示它们的接口而不是实现时。
参考文章
二十三种设计模式及其python实现
缺点
抽象工厂方法的一个弊端是,每次新增具体的业务类时,都需要在对于的工厂类中新增一个类型。
改良
因为元类是可以在声明类对象时,进行一些前置动作的,如果在类声明时,将整个类对象按类名:类对象存储在一个字典里面,工厂方法按类名获取到类对象,弥补需手动修改代码的缺点
实践代码如下
"""
A.实践 工厂模式 和抽象工厂模式
场景 adb通过连接设备
连接类型
1. usb连接
2. wifi连接
设备类型
3. 手机
4. 平板
B. 使用元类,自动注册工厂类
"""
class ConnectionTypeError(Exception):
pass
class DeviceTypeError(Exception):
pass
class FactoryTypeError(Exception):
pass
class ConnectionStack:
"""
存储连接对象
"""
connection_map = dict()
@classmethod
def register(cls, name, obj):
print(f"ConnectionStack 注册类对象{name}")
cls.connection_map[name] = obj
@classmethod
def get_connection_cls(cls, name):
return cls.connection_map.get(name)
class DeviceStack:
"""
存储设备类对象
"""
device_map = dict()
@classmethod
def register(cls, name, obj):
cls.device_map[name] = obj
print(f"DeviceStack 注册类对象{name}")
@classmethod
def get_device_cls(cls, name):
return cls.device_map.get(name)
class ConnectionMete(type):
"""
连接类的元类,
1. 将类对象保存在ConnectionStack;
2. 通过类名获取类对象 eg:ConnectionStack.get_connection_cls(class_name)
"""
def __new__(cls, cls_name, cls_base, cls_dict):
cls_obj = super(ConnectionMete, cls).__new__(cls, cls_name, cls_base, cls_dict)
ConnectionStack.register(cls_name, cls_obj)
return cls_obj
class DeviceMete(type):
"""
设备类的元类,
1. 将类对象保存在 DeviceStack;
2. 通过类名获取类对象 eg: DeviceStack.get_device_cls(class_name)
"""
def __new__(cls, cls_name, cls_base, cls_dict):
cls_obj = super(DeviceMete, cls).__new__(cls, cls_name, cls_base, cls_dict)
DeviceStack.register(cls_name, cls_obj)
return cls_obj
class Connection(metaclass=ConnectionMete):
"""
设备基类
"""
def connect(self, connection_id):
pass
def disconnect(self, connection_id):
pass
def execute_cmd(self, cmd):
pass
class USBConnection(Connection):
"""
工厂方法模式,每个连接都有一个独立的类
"""
def connect(self, connection_id):
print(f"设备【{connection_id}】通过usb建立连接")
class WIFIConnection(Connection):
"""
工厂方法模式,每个连接都有一个独立的类
"""
def connect(self, connection_id):
print(f"设备【{connection_id}】通过wifi建立连接")
class ConnectionFactory:
"""
工厂模式-返回连接对象实例
"""
def create_connection(self, connection_cls_name):
connection = ConnectionStack.get_connection_cls(connection_cls_name)
if connection:
return connection()
else:
raise ConnectionTypeError
class Device(metaclass=DeviceMete):
def boot_app(self, package_name):
pass
class Mobile(Device):
def boot_app(self, package_name):
print(f"在 mobile上启动应用{package_name}")
class Pad(Device):
def boot_app(self, package_name):
print(f"在 pad上启动应用{package_name}")
class DeviceFactory:
"""
设备工厂
"""
def create_device(self, device_cls_name):
device = DeviceStack.get_device_cls(device_cls_name)
if device:
return device()
else:
raise DeviceTypeError
class ManagerFactory:
"""
管理工厂
抽象工厂模式的核心,还回一个具体的工厂
"""
def __init__(self):
self.factory_map = {
'connection': ConnectionFactory,
'device': DeviceFactory,
}
def get_factory(self, factory_name):
factory = self.factory_map.get(factory_name)
if factory:
return factory()
else:
raise FactoryTypeError(f"工厂类型错误:{factory_name} not in {self.factory_map.keys()}")
if __name__ == "__main__":
# 工厂方法
con_factory = ConnectionFactory()
usb = con_factory.create_connection("USBConnection")
usb.connect("aaaaaa")
dev_factory = DeviceFactory()
mobile = dev_factory.create_device("Mobile")
mobile.boot_app("123.apk")
# 调用抽象工厂
factory = ManagerFactory()
dev_factory = factory.get_factory('device')
# 获取 pad 设备
pad = dev_factory.create_device("Pad")
pad.boot_app("1111.apk")