Design Patterns——<三>中介模式

一、什么是中介模式

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other eaxplicitly, and it lets you vary their interaction independently.
用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

中介模式又称调停模式。在很多系统中,多个类很容易相互耦合形成网状结构。中介模式的作用就是讲网状结构分离成星型结构,使得对象间的结构更加简洁,交互更加顺畅。
在这里插入图片描述


二、代码框架

class InteractiveObject:
    '''进行交互的对象'''
    pass

class InteractiveObjectImplA:
    '''实现类A'''
    pass

class InteractiveObjectImplB:
    '''实现类B'''
    pass

class Mediator:
    '''中介类'''
    def __init__(self) -> None:
        self._interactiveObjA = InteractiveObjectImplA()
        self._interactiveObjB = InteractiveObjectImplB()
        
    def interactive(self):
        '''交互操作'''
        # 通过self._interactiveObjA和self._interactiveObjB完成相应的交互操作
        pass

在这里插入图片描述

中介模式UML类图

三、应用

不管是QQ、微信这类支持视频通信的社交软件,还是互联网在线教育产品,都需要和通信设备(扬声器、麦克风、摄像头)进行交互。在PC端,你可能会有多个扬声器、多个摄像头,还可能会在通话过程中进行麦克风切换。如何与这些繁杂的设备进行交互呢?


在这里插入图片描述

中介模式实现设备管理器——UML类图

'''
@author: zyh
@time: 2023/5/5 15:30
@file: mediator.py
'''

from abc import ABCMeta, abstractmethod
from enum import Enum

class DeviceType(Enum):
    '''设备类型'''
    TypeSpeaker = 1
    TypeMicrophone = 2
    TypeCamera = 3
    
class DeviceItem:
    '''设备项'''
    def __init__(self, id, name, type, isDefault = False):
        self._id = id
        self._name = name
        self._type = type
        self._isDefault = isDefault
        
    def __str__(self) -> str:
        return 'type: ' + str(self._type) + ', id: ' + str(self._id) + ', name: ' + str(self._name) + ', isDefault: ' + str(self._isDefault)
    
    def getId(self):
        return self._id
    
    def getName(self):
        return self._name
    
    def getType(self):
        return self._type
    
    def isDefault(self):
        return self._isDefault

class DeviceList:
    '''设备列表'''
    def __init__(self):
        self._devices = []
        
    def addDevice(self, deviceItem):
        self._devices.append(deviceItem)
        
    def getCount(self):
        return len(self._devices)
    
    def getByIdx(self, idx):
        if idx < 0 or idx >= len(self._devices):
            return None
        return self._devices[idx]
    
    def getById(self, id):
        for item in self._devices:
            if item.getId() == id:
                return item
        return None
    
class DeviceManager(metaclass=ABCMeta):
    
    @abstractmethod
    def emumerate(self):
        '''枚举设备列表(在程序初始化时,有设备插拔时都要重新获取设备列表)'''
        pass
    
    @abstractmethod
    def active(self, deviceId):
        '''选择要使用的设备'''
        pass
    
    @abstractmethod
    def getCurDeviceId(self):
        '''获取当前正在使用设备的Id'''
        pass
    
class SpeakerManager(DeviceManager):
    '''扬声器设备管理器'''
    def __init__(self) -> None:
        super().__init__()
        self._curDeviceId = None
        
    def emumerate(self):
        '''枚举设备列表(真实项目中应该通过驱动程序去读取设备信息,这里仅初始化作为模拟)'''
        devices = DeviceList()
        devices.addDevice(DeviceItem('369dd760-893b', 'Realtek High Definition Audio', DeviceType.TypeSpeaker))
        devices.addDevice(DeviceItem('59357639-6a43', 'NVIDIA High Definition Audio', DeviceType.TypeSpeaker, True))
        return devices
    
    def active(self, deviceId):
        '''激活指定的设备作为当前要用的设备'''
        self._curDeviceId = deviceId
        
    def getCurDeviceId(self):
        return self._curDeviceId
    
class DeviceUtil:
    '''设备工具类'''
    def __init__(self) -> None:
        self._mgrs = {}
        self._mgrs[DeviceType.TypeSpeaker] = SpeakerManager()
        # 为节省篇幅,MicrophoneManager和CameraManager不再实现
        
    def _getDeviceManager(self, type):
        return self._mgrs[type]
    
    def getDeviceList(self, type):
        return self._getDeviceManager(type).emumerate()
    
    def active(self, type, deviceId):
        self._getDeviceManager(type).active(deviceId)
        
    def getCurDeviceId(self, type):
        return self._getDeviceManager(type).getCurDeviceId()

def testDevices():
    deviceUtil = DeviceUtil()
    deviceList = deviceUtil.getDeviceList(DeviceType.TypeSpeaker)
    print('麦克风设备列表:')
    if deviceList.getCount() > 0:
        # 设置第1个设备为要用的设备
        deviceUtil.active(DeviceType.TypeSpeaker, deviceList.getByIdx(0).getId())
    for idx in range(deviceList.getCount()):
        device = deviceList.getByIdx(idx)
        print(device)
    print('当前使用的设备为:' + deviceList.getById(deviceUtil.getCurDeviceId(DeviceType.TypeSpeaker)).getName())
    
if __name__ == '__main__':
    testDevices()

输出:

麦克风设备列表:
type: DeviceType.TypeSpeaker, id: 369dd760-893b, name: Realtek High Definition Audio, isDefault: False
type: DeviceType.TypeSpeaker, id: 59357639-6a43, name: NVIDIA High Definition Audio, isDefault: True  
当前使用的设备为:Realtek High Definition Audio

四、补充说明

中介者本质上是提供了一个平台,并没有提供实际的行为。

优点:

  1. 简化了对象之间的交互;
  2. 将多对多的交互关系转换为一对多的交互关系,更易于理解、维护和拓展;
  3. 便于复用、降低耦合。

缺点:

  1. 中介者类承接了所有的交互逻辑,中介者类会变得越来越庞大和复杂,以至于难以维护;
  2. 中介者出问题会导致多个对象出问题。

应用场景:

  1. 一组对象以定义良好但复杂的方式进行通信,产生的依赖结构混乱难以理解;
  2. 一个对象引用其他很多对象并且直接与这些对象通信,导致该对象难以复用;
  3. 想通过一个中间类来封装多个类中的行为,同时又不想生成太多的子类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值