【再谈设计模式】中介者模式 - 协调对象间交互的枢纽

简介: 中介者模式定义了一个中介对象来封装一组对象之间的交互方式。中介者使得各对象之间不需要显式地相互引用,从而降低了它们之间的耦合度。它通过将对象之间的交互逻辑集中到中介者对象中,使得系统的结构更加清晰,易于维护和扩展。

{62146138-A03B-4CC4-B3C8-328068F5A4A8}.png

一、引言

在复杂的软件系统中,对象之间的交互往往错综复杂。当众多对象相互依赖、频繁通信时,系统的耦合度会急剧上升,导致代码难以维护、扩展和理解。就像在一个大型社交聚会中,如果每个人都直接与其他人交流,场面会变得混乱不堪。中介者模式的出现,就如同一位社交组织者,它简化了对象之间的交互关系,使系统更加有序和易于管理。

二、定义与描述

中介者模式定义了一个中介对象来封装一组对象之间的交互方式。中介者使得各对象之间不需要显式地相互引用,从而降低了它们之间的耦合度。它通过将对象之间的交互逻辑集中到中介者对象中,使得系统的结构更加清晰,易于维护和扩展。

三、抽象背景

在面向对象的软件设计中,随着系统功能的不断增加,对象之间的交互逻辑会变得越来越复杂。例如,在一个图形用户界面(GUI)系统中,多个按钮、文本框和菜单之间可能存在复杂的交互关系,如点击按钮可能会影响文本框的显示内容,菜单的选择可能会改变按钮的可用性等。如果不采用合适的设计模式,这些对象之间的直接交互会导致代码的高度耦合,任何一个对象的改变都可能影响到其他多个对象。

四、适用场景与现实问题解决

(一)适用场景

GUI组件交互

在桌面应用程序的GUI开发中,多个控件(如按钮、文本框、下拉菜单等)之间存在复杂的交互逻辑。中介者模式可以将这些控件之间的交互逻辑封装在中介者对象中,使得每个控件只需与中介者对象交互,而不需要知道其他控件的具体情况。
{C471510D-4A27-45BE-B8BD-2EAC73C24887}.png

游戏开发中的角色交互

在多人游戏中,不同角色之间可能存在各种交互,如交易、战斗、组队等。使用中介者模式可以将角色之间的交互逻辑集中管理,便于游戏逻辑的维护和扩展。

分布式系统中的节点通信

在分布式系统中,多个节点需要相互通信以协调工作。中介者模式可以通过一个中介节点来管理其他节点之间的通信,简化通信协议和逻辑。

(二)现实问题解决

降低耦合度

传统的对象间直接交互会导致对象之间紧密耦合,一个对象的变化可能需要修改多个与之相关的对象。中介者模式将对象间的交互转移到中介者对象中,使得对象之间的依赖关系减少。例如,在一个电商系统中,订单处理、库存管理和用户通知等模块之间存在复杂的交互。如果采用中介者模式,这些模块只需与中介者交互,当订单处理模块发生变化时,不会直接影响库存管理和用户通知模块,只需要调整中介者中的相关逻辑即可。

简化复杂交互逻辑

    当多个对象之间存在多对多的交互关系时,交互逻辑会变得非常复杂。中介者模式将这些复杂的交互逻辑集中到中介者对象中,使得系统的整体逻辑更加清晰。例如,在一个航空订票系统中,乘客、航班、航空公司等多个对象之间存在复杂的交互关系,如航班变更时需要通知乘客和航空公司进行相应的调整。通过中介者模式,可以将这些交互逻辑集中到一个订票中介者对象中,便于管理和维护。

{862AD808-ABF3-431A-9C62-54A73AA5EFAF}.png

五、中介者模式的现实生活的例子

机场塔台

在机场中,飞机(多个对象)之间不能直接相互指挥飞行路径等操作,而是通过机场塔台(中介者)来协调。塔台接收来自各个飞机的请求(如起飞、降落、等待等),并根据整体的机场运行情况(如跑道占用、天气状况等)向飞机发出指令,以确保机场的安全和高效运行。
{F9CC3E72-7DD2-4332-AAE6-563527FCB9A8}.png

房屋中介

在房地产交易中,卖家和买家(多个对象)之间通常不会直接协商房屋交易的所有细节。房屋中介(中介者)作为中间角色,收集卖家的房屋信息和价格期望,以及买家的购房需求和预算,然后协调双方进行看房、议价等活动,最终促成交易。

六、初衷与问题解决

初衷

中介者模式的初衷是为了降低对象之间的耦合度,提高系统的可维护性和可扩展性。当系统中的对象数量增加,对象之间的交互关系变得复杂时,通过引入中介者对象,可以将复杂的多对多交互关系简化为对象与中介者之间的一对多关系。

问题解决

如前面所述,它解决了对象之间的高度耦合问题,使得系统在面临需求变更或功能扩展时,不需要对大量的对象进行修改。同时,也简化了复杂的交互逻辑,提高了系统的整体清晰度,便于开发人员理解和维护系统。

七、代码示例

类图:

{E3B0BD57-3A97-4919-B797-C8BC2E2AE6D5}.png

(一)Java示例

// 中介者接口interface Mediator {    void notify(Colleague colleague);
}// 同事类抽象类abstract class Colleague {    protected Mediator mediator;    public Colleague(Mediator mediator) {        this.mediator = mediator;
    }    abstract void receive();    abstract void send();
}// 具体同事类Aclass ConcreteColleagueA extends Colleague {    public ConcreteColleagueA(Mediator mediator) {        super(mediator);
    }    @Override
    void receive() {
   
        System.out.println("ConcreteColleagueA received a message");
    }    @Override
    void send() {
   
        System.out.println("ConcreteColleagueA sends a message");
        mediator.notify(this);
    }
}// 具体同事类Bclass ConcreteColleagueB extends Colleague {    public ConcreteColleagueB(Mediator mediator) {        super(mediator);
    }    @Override
    void receive() {
   
        System.out.println("ConcreteColleagueB received a message");
    }    @Override
    void send() {
   
        System.out.println("ConcreteColleagueB sends a message");
        mediator.notify(this);
    }
}// 具体中介者类class ConcreteMediator implements Mediator {    private ConcreteColleagueA colleagueA;    private ConcreteColleagueB colleagueB;    public void setColleagueA(ConcreteColleagueA colleagueA) {        this.colleagueA = colleagueA;
    }    public void setColleagueB(ConcreteColleagueB colleagueB) {
           this.colleagueB = colleagueB;
    }    @Override
    public void notify(Colleague colleague) {
           if (colleague == colleagueA) {
   
            colleagueB.receive();
        } else {
   
            colleagueA.receive();
        }
    }
}// 测试类public class MediatorPatternJava {    public static void main(String[] args) {        ConcreteMediator mediator = new ConcreteMediator();        ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);        ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);
        mediator.setColleagueA(colleagueA);
        mediator.setColleagueB(colleagueB);
        colleagueA.send();
        colleagueB.send();
    }
}

流程图:
{CA8AD525-20B3-4582-889C-BA5DBECA0978}.png

时序图:
{33180A37-FC57-4172-9EAF-6052814CFB13}.png

(二)C++示例

#include <iostream>// 中介者类class Mediator {public:    virtual void notify(class Colleague *colleague) = 0;
};// 同事类抽象类class Colleague {protected:
    Mediator *mediator;public:    Colleague(Mediator *m) : mediator(m) {
   }    virtual void receive() = 0;    virtual void send() = 0;
};// 具体同事类Aclass ConcreteColleagueA : public Colleague {public:    ConcreteColleagueA(Mediator *m) : Colleague(m) {}    void receive() override {
   
        std::cout << "ConcreteColleagueA received a message" << std::endl;
    }    void send() override {
   
        std::cout << "ConcreteColleagueA sends a message" << std::endl;
        mediator->notify(this);
    }
};// 具体同事类Bclass ConcreteColleagueB : public Colleague {public:    ConcreteColleagueB(Mediator *m) : Colleague(m) {}    void receive() override {
   
        std::cout << "ConcreteColleagueB received a message" << std::endl;
    }    void send() override {
   
        std::cout << "ConcreteColleagueB sends a message" << std::endl;
        mediator->notify(this);
    }
};// 具体中介者类class ConcreteMediator : public Mediator {private:
    ConcreteColleagueA *colleagueA;
    ConcreteColleagueB *colleagueB;public:    void setColleagueA(ConcreteColleagueA *a) {
   
        colleagueA = a;
    }    void setColleagueB(ConcreteColleagueB *b) {
   
        colleagueB = b;
    }    void notify(Colleague *colleague) override {
           if (colleague == colleagueA) {
   
            colleagueB->receive();
        } else {
   
            colleagueA->receive();
        }
    }
};// 测试函数int main() {
   
    ConcreteMediator mediator;    ConcreteColleagueA colleagueA(&mediator);    ConcreteColleagueB colleagueB(&mediator);
    mediator.setColleagueA(&colleagueA);
    mediator.setColleagueB(&colleagueB);
    colleagueA.send();
    colleagueB.send();    return 0;
}

(三)Python示例

# 中介者类class Mediator:    def notify(self, colleague):        pass# 同事类抽象类class Colleague:    def __init__(self, mediator):
        self.mediator = mediator    def receive(self):        pass

    def send(self):        pass# 具体同事类Aclass ConcreteColleagueA(Colleague):    def receive(self):        print("ConcreteColleagueA received a message")    def send(self):        print("ConcreteColleagueA sends a message")
        self.mediator.notify(self)# 具体同事类Bclass ConcreteColleagueB(Colleague):    def receive(self):        print("ConcreteColleagueB received a message")    def send(self):        print("ConcreteColleagueB sends a message")
        self.mediator.notify(self)# 具体中介者类class ConcreteMediator(Mediator):    def __init__(self):
        self.colleagueA = None
        self.colleagueB = None

    def set_colleagueA(self, colleagueA):
        self.colleagueA = colleagueA    def set_colleagueB(self, colleagueB):
        self.colleagueB = colleagueB    def notify(self, colleague):        if colleague == self.colleagueA:
            self.colleagueB.receive()        else:
            self.colleagueA.receive()# 测试代码if __name__ == "__main__":
    mediator = ConcreteMediator()
    colleagueA = ConcreteColleagueA(mediator)
    colleagueB = ConcreteColleagueB(mediator)
    mediator.set_colleagueA(colleagueA)
    mediator.set_colleagueB(colleagueB)
    colleagueA.send()
    colleagueB.send()

(四)Go示例

package mainimport (    "fmt")// 中介者接口type Mediator interface {
   
    notify(colleague Colleague)
}// 同事类接口type Colleague interface {
   
    receive()
    send()
}// 具体同事类Atype ConcreteColleagueA struct {
   
    mediator Mediator
}func (c *ConcreteColleagueA) receive() {
   
    fmt.Println("ConcreteColleagueA received a message")
}func (c *ConcreteColleagueA) send() {
   
    fmt.Println("ConcreteColleagueA sends a message")
    c.mediator.notify(c)
}// 具体同事类Btype ConcreteColleagueB struct {
   
    mediator Mediator
}func (c *ConcreteColleagueB) receive() {
   
    fmt.Println("ConcreteColleagueB received a message")
}func (c *ConcreteColleagueB) send() {
   
    fmt.Println("ConcreteColleagueB sends a message")
    c.mediator.notify(c)
}// 具体中介者类type ConcreteMediator struct {
   
    colleagueA *ConcreteColleagueA
    colleagueB *ConcreteColleagueB
}func (m *ConcreteMediator) notify(colleague Colleague) {
       if _, ok := colleague.(*ConcreteColleagueA); ok {
   
        m.colleagueB.receive()
    } else {
   
        m.colleagueA.receive()
    }
}func main() {
   
    mediator := &ConcreteMediator{
   }
    colleagueA := &ConcreteColleagueA{
   mediator}
    colleagueB := &ConcreteColleagueB{
   mediator}
    mediator.colleagueA = colleagueA
    mediator.colleagueB = colleagueB
    colleagueA.send()
    colleagueB.send()
}

八、中介者模式的优缺点

{B11F162F-8DA7-44D7-96AB-3DE981752885}.png

(一)优点

降低耦合度

对象之间不再直接交互,而是通过中介者进行通信,大大降低了对象之间的依赖关系,使得系统更加灵活,易于维护和扩展。

简化对象交互逻辑

将复杂的多对多对象交互逻辑集中到中介者对象中,使得交互逻辑更加清晰,便于理解和管理。

提高代码复用性

中介者对象可以被多个对象复用,提高了代码的复用性。

(二)缺点

中介者可能变得复杂

随着系统功能的增加,中介者对象可能会承担过多的交互逻辑,变得过于复杂,难以维护。

降低对象的自主性

对象的行为在一定程度上依赖于中介者,可能会降低对象自身的自主性和可复用性。
{445BADEE-F9DF-4F46-9982-CDA03A9014CA}.png

九、中介者模式的升级版

{661AC527-84D2-4B8B-9926-AEC98F029F1C}.png

分层中介者模式

在大型系统中,可以采用分层中介者模式。将中介者分为多个层次,每个层次的中介者负责处理特定范围内的对象交互。例如,在企业级应用中,可以有部门级中介者和公司级中介者。部门级中介者处理部门内部对象的交互,公司级中介者协调部门之间的交互。这种分层结构可以进一步降低耦合度,提高系统的可维护性和扩展性。

分布式中介者模式

在分布式系统中,可以采用分布式中介者模式。将中介者功能分布在多个节点上,通过网络通信来协调对象之间的交互。这种模式可以提高系统的容错性和性能,适用于大规模分布式应用场景。

目录
相关文章
|
2天前
|
设计模式 Java Go
【再谈设计模式】状态模式~对象行为的状态驱动者
状态模式属于行为型设计模式。它将对象的行为封装在不同的状态类中,使得对象在不同的状态下表现出不同的行为。上下文(Context):这是一个包含状态对象的类,它定义了客户感兴趣的接口,并维护一个具体状态对象的引用。上下文将操作委托给当前的状态对象来处理。抽象状态(State):这是一个抽象类或者接口,它定义了一个特定状态下的行为接口。所有具体的状态类都实现这个接口。具体状态(Concrete State):这些是实现抽象状态接口的类,每个具体状态类实现了与该状态相关的行为。
31 18
|
15小时前
|
分布式计算 并行计算 调度
基于HPC场景的集群任务调度系统LSF/SGE/Slurm/PBS
在HPC场景中,集群任务调度系统是资源管理和作业调度的核心工具。LSF、SGE、Slurm和PBS是主流调度系统。LSF适合大规模企业级集群,提供高可靠性和混合云支持;SGE为经典开源系统,适用于中小规模集群;Slurm成为HPC领域事实标准,支持多架构和容器化;PBS兼具商业和开源版本,擅长拓扑感知调度。选型建议:超大规模科研用Slurm,企业生产环境用LSF/PBS Pro,混合云需求选LSF/PBS Pro,传统小型集群用SGE/Slurm。当前趋势显示Slurm在TOP500系统中占比超60%,而商业系统在金融、制造等领域保持优势。
36 24
|
14小时前
|
存储 SQL 关系型数据库
服务器数据恢复—云服务器上mysql数据库数据恢复案例
某ECS网站服务器,linux操作系统+mysql数据库。mysql数据库采用innodb作为默认存储引擎。 在执行数据库版本更新测试时,操作人员误误将在本来应该在测试库执行的sql脚本在生产库上执行,导致生产库上部分表被truncate,还有部分表中少量数据被delete。
29 17
|
15小时前
|
人工智能 语音技术 开发者
千问max#百炼AI实训课作业#科幻小说家
根据教程一步步操作确实有趣,尤其是语音识别的准确度很高,带来了很好的开发体验。通过详细步骤引导,开发者可以轻松上手并实现高质量的语音交互功能。
|
17天前
|
机器学习/深度学习 存储 算法
《匿名化技术:数据隐私与价值挖掘的平衡探索》
在数据驱动的时代,数据成为企业和组织的核心资产,匿名化技术作为保护数据隐私的重要手段备受关注。它通过去除或混淆个人身份信息,如数据脱敏、泛化和加密等方法,有效保护隐私。然而,匿名化可能影响数据的完整性和准确性,进而影响价值挖掘。为平衡隐私保护与数据利用,需明确使用目的、加强数据治理、创新技术应用,确保数据安全合规,推动数字经济健康发展。
77 30
|
1月前
|
人工智能 运维 监控
操作系统智能助手OS Copilot新功能测评
本文介绍了操作系统智能助手OS Copilot的新功能测评。作为一名运维工程师,作者分享了安装过程中遇到的小问题及解决方法,并详细描述了使用体验。OS Copilot在回答速度、命令执行和任务处理方面表现一般,但提供了便捷的自动化操作,适合新手学习。作者指出其优点包括深度定制化、简化重复工作和对新手友好;不足之处在于回答不够流畅、汉化程度低且智能化水平有待提高。整体评分6分,未来有提升空间。
|
1月前
|
存储 人工智能 自然语言处理
|
3天前
|
人工智能 自然语言处理 安全
2025最新排名|盘点值得推荐的5个在线客服系统
在数字化浪潮下,在线客服系统迅速发展,成为企业提升竞争力的关键。本文推荐五款2025年值得使用的在线客服系统:合力亿捷、淘宝、京东、华为云和中国移动客服系统。它们各自具备全渠道接入、智能问答、数据分析、高稳定性等亮点,助力企业高效服务客户,优化营销策略并提升整体运营效率。
43 24
|
4天前
|
Linux 开发工具 git
Docker 101
Docker is a practical tool for everyday use, and like `Git`, you can learn it in just 30 minutes.
53 35
Docker 101
|
24天前
|
小程序 数据安全/隐私保护
跑腿小程序系统源码
这是一款跑腿小程序,带有智能派单、系统派单、同城配送、校园跑腿、预约取件、用户端+骑手端 基于FastAdmin+thinkphp和uniapp开发的优创同城跑腿系统,支持帮取、帮送模式,包含用户端、骑手端、运营后台。
66 32