C++设计模式——中介者模式(Mediator Pattern)

C++设计模式——中介者模式(Mediator Pattern)

微信公众号:幼儿园的学霸

目录

文章目录

  • C++设计模式——中介者模式(Mediator Pattern)
  • 目录
  • 引言
  • 定义
  • 代码示例
  • 总结
  • 参考资料

引言

假设现在科技发达之后,家里所有设备都是智能化的,而小明在家洗澡的时候有个习惯就是喜欢听歌,而且洗澡时候还要把窗帘拉上。因此就有这种情形,小明要拉窗帘可能就是要洗澡,当然也要听歌,因此我们希望小明家的洗浴设备,音响设备和窗帘设备都能协同合作,不管操作哪种设备,其他两种设备都有一定响应,以此写出程序。

现在很明显我们可以看出来,我们有三个对象,也就是三种设备,程序看起来也很简单,只要打卡一个设备,这个设备再打开其他两个设备就好啦,只要在一个设备的类里放两个其他设备的 引用,很容易就搞定了,当然这样最简单啦,这样写出来的程序对象关系如下图:
C++设计模式——中介者模式(Mediator Pattern)_第1张图片

这个程序最主要的功能就是在一个类里完成了对另外两个类的方法作用。但是这样设计有两个主要缺陷(其实是对象之间耦合度过高而引起的):
1.一旦窗帘设备坏掉,需要更换,那样我们就要让新的窗帘设备建立别的设备的连接,这样会很麻烦
2.如果我们又有别的需求,比如洗澡的时候要把门锁住,那门锁的智能设备又要关联所有设备,更加麻烦.

也就是说多个类相互耦合,形成了网状结构,它要求每个对象都必须知道它需要交互的对象。

将上述网状结构分离为星型结构,将大大降低它们之间的“耦合性”,而这就是中介模式,中介者模式下的对象交互如下图:
C++设计模式——中介者模式(Mediator Pattern)_第2张图片

其实中介者就好比智能家居的管家,这样所有对象的交互指令都通过它来传达,这样这个中介者负责与对象之间联系,对象与对象之间不再进行直接的交互,也就是对对象关系 进行解耦。

以上,对中介模式有了一个初步的认识:
当对象与对象之间存在大量的关联关系时,势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。当引入中介后,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

定义

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

定义:用一个中介对象来封装一系列对象交互。中介者使各对象不需要相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,属于行为型模式。

设计思路:用一个中介对象来封装一系列的对象交互操作,中介者模式使得对象之间不需要显示的相互引用,从而使得系统或模块内部相互解耦,而且可以独立的改变它们至今的交互。

中介者模式的本质:封装交互: 将交互过程封装起来

中介者模式包含以下主要角色:

  • 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法;定义一个接口用于与各同事对象通信;
  • 具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,了解并维护它的各个同事,因此它依赖于同事角色;
  • 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能;
  • 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象通信/交互时,与中介者通信即可,而后由中介者对象负责后续的交互;因此每一个具体同事类需要知道中介者对象,而不需要了解其他同事类的情况。

其UML类图如下图所示:
C++设计模式——中介者模式(Mediator Pattern)_第3张图片

代码示例

以租房为例,中介者模式其实就相当于:中介,求租者,还有房东三者之间的关系。
房东,租房人A、B联系了中介,在中介那里记名字了。
房东有空房了,发条消息给中介,中介将房东有空房的消息发给求租者。
当求租者A联系中介发了条消息,房东与求租者B都会收到A的消息。

关键代码:对象 Colleague 之间的通信封装到一个类中单独处理

#include 


//
//中介者模式
//关键代码:对象 Colleague 之间的通信封装到一个类中单独处理
//


class Mediator;

//抽象人
class Person {
protected:
    std::shared_ptr m_mediator; //中介
public:
    Person(const std::shared_ptr pMediator)
            : m_mediator(pMediator) {}

    virtual ~Person() = default;//虚析构函数

    //向中介发送信息
    virtual void SendMessage(const std::string &message) = 0;

    //从中介获取信息
    //message 中介向该对象发送的信息/从中介获取的信息
    virtual void GetMessage(const std::string &message) = 0;
};

//抽象中介机构
class Mediator {
public:
    virtual ~Mediator() = default;

    //由于后面this指针的原因,此处未采用智能指针
    virtual void Send(std::string message, const Person *from_person) const = 0;

    virtual void Register(std::shared_ptr pPerson) = 0;
};

//租房者A
class RenterA : public Person {
public:
    RenterA(const std::shared_ptr mediator) : Person(mediator) {}

    void SendMessage(const std::string &message) override {
        m_mediator->Send(message, this);
    }

    void GetMessage(const std::string &message) override {
        std::cout << "租房者A收到信息" << message << std::endl;;
    }
};

//租房者B
class RenterB : public Person {
public:
    RenterB(const std::shared_ptr mediator) : Person(mediator) {}

    void SendMessage(const std::string &message) override {
        m_mediator->Send(message, this);
    }

    void GetMessage(const std::string &message) override {
        std::cout << "租房者B收到信息" << message << std::endl;;
    }
};


//房东
class Landlord : public Person {
public:
    Landlord(const std::shared_ptr mediator) : Person(mediator) {}

    void SendMessage(const std::string &message) override {
        m_mediator->Send(message, this);
    }

    void GetMessage(const std::string &message) override {
        std::cout << "房东收到信息:" << message << std::endl;;
    }
};

//房屋中介
class HouseMediator : public Mediator {
private:
    //也可以采用多个list,将多个房东放入一个list,将多个求租者放入一个list
    std::vector> m_pPersonList;
public:
    void Register(const std::shared_ptr pPerson) override {
        //没有添加该同事,则添加进去
        auto iter = m_pPersonList.begin();
        for (; iter != m_pPersonList.end(); ++iter) {
            if (*iter == pPerson)
                break;
        }

        if (iter == m_pPersonList.end())
            m_pPersonList.emplace_back(pPerson);

    }

    void Send(std::string message, const Person *from_person) const override {
        //接收消息的对象为该对象的对应对象
        //
        for (const auto item:m_pPersonList) {
            //此处采用typeid,而非直接判断指针是否相等为同一个对象.
            // 具体何种方式,一般区别不大,视情况而定
            if (typeid(*item.get()) != typeid(*from_person))
                //if( item.get() != from_person)
                item->GetMessage(message);
        }
    }
};

int main() {
    std::shared_ptr pHouseMediator = std::make_shared();
    std::shared_ptr pRenterA = std::make_shared(pHouseMediator);
    std::shared_ptr pRenterB = std::make_shared(pHouseMediator);
    std::shared_ptr pLandlord = std::make_shared(pHouseMediator);

    pHouseMediator->Register(pRenterA);
    pHouseMediator->Register(pRenterB);
    pHouseMediator->Register(pLandlord);

    pLandlord->SendMessage("出租房子:中山路100号,50平米,2000元一个月");//所有的求租者将会收到该消息

    std::cout << std::string(50, '-') << std::endl;

    pRenterA->SendMessage("我想在中山路附近租套房子,价格1500元一个月");//所有的房东将会收到该消息

    return 0;

    //运行结果如下:
    //租房者A收到信息出租房子:中山路100号,50平米,2000元一个月
    //租房者B收到信息出租房子:中山路100号,50平米,2000元一个月
    //--------------------------------------------------
    //租房者B收到信息我想在中山路附近租套房子,价格1500元一个月
    //房东收到信息:我想在中山路附近租套房子,价格1500元一个月
}

需要注意的是,在中介者中传递消息的时候需要判断当前参数中指向的对象是哪种类型,用到了操作符typeid。它的参数类型是对象,若两个对象是同一个类型则返回true。

从运行结果可以看到:当求租者A联系中介发了条消息,房东与求租者B都会收到A的消息,这个不是很合理,有待改进。我们可以将HouseMediator类进行改进,加入一些必要的判断等措施,保证房东的消息只发给求租者,而求租者的消息只有房东可以收到。改进的一些思路在代码中已经有所体现,感兴趣的可以进行尝试。

总结

优点:
1.降低了类的复杂度,将一对多关联转化成了一对一的关联,提高了系统的灵活性,使得系统易于维护和扩展;
2.降低了对象之间的耦合性,使得对象易于独立地被复用;
3.符合迪米特原则:只与你最直接的朋友交流(Only talk to you immediate friends.)。

中介者模式是应用迪米特法则的典型

缺点:
当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。

参考资料

1.中介者模式详解
2.设计模式入门——中介者模式(mediator)



下面的是我的公众号二维码图片,按需关注。
图注:幼儿园的学霸

你可能感兴趣的:(C++,设计模式,c++)