python 抽象工厂实践+ 元类自动注册工厂类

2021-10-22  本文已影响0人  逐风细雨

抽象工厂定义

   提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

适用性

缺点

   抽象工厂方法的一个弊端是,每次新增具体的业务类时,都需要在对于的工厂类中新增一个类型。

改良

   因为元类是可以在声明类对象时,进行一些前置动作的,如果在类声明时,将整个类对象按类名:类对象存储在一个字典里面,工厂方法按类名获取到类对象,弥补需手动修改代码的缺点

实践代码如下

"""
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")

运行后的控制台输出

image.png
上一篇下一篇

猜你喜欢

热点阅读