天天看點

C++中介者模式簡述模式結構優缺點适用場景案例分析代碼實作

簡述

中介者模式(Mediator Pattern)用一個中介對象來封裝一系列的對象互動。中介者使各對象不需要顯式地互相引用,進而使其耦合松散,而且可以獨立地改變它們之間的互動。

版權所有:一去丶二三裡,轉載請注明出處:

http://blog.csdn.net/liang19890820

UML 結構圖:

  • Mediator(抽象中介者):為 Colleague 對象之間的通信定義接口。
  • ConcreteMediator(具體中介者):實作 Mediator 接口,并需要了解和維護各個 Colleague 對象,負責協調他們之間的通信。
  • Colleague(抽象同僚類):定義與其他 Colleague 通信的接口。
  • ConcreteColleague (具體同僚類):實作 Colleague 接口,并通過 Mediator 與其他 Colleague 進行溝通。

中介者是對象的通信中心。當一個對象需要與另一個對象通信時,它不會直接調用另一個對象。相反,它會調用中介者對象,其主要職責是将消息路由到目标對象。它允許開發人員不必管理對象之間的連結。

優點:

  • 中介者模式簡化了對象之間的互動,它用中介者和同僚的一對多互動代替了原來同僚之間的多對多互動,一對多關系更容易了解、維護和擴充,将原本難以了解的網狀結構轉換成相對簡單的星型結構。
  • 中介者模式可将各同僚對象解耦。中介者有利于各同僚之間的松耦合,可以獨立地改變和複用每一個同僚和中介者,增加新的中介者和新的同僚類都比較友善,更好地符合“開閉原則”。
  • 可以減少子類生成,中介者将原本分布于多個對象間的行為集中在一起,改變這些行為隻需生成新的中介者子類即可,這使各個同僚類可被重用,無須對同僚類進行擴充。

缺點:

  • 如果存在大量同僚之間的互動,中介者将會變得非常複雜,使得系統難以維護。

  • 系統中對象之間存在比較複雜的引用關系,導緻它們之間的依賴關系結構混亂而且難以複用該對象。
  • 想通過一個中間類來封裝多個類中的行為,而又不想生成太多的子類。

中介 - 客戶與房東之間的橋梁

說起中介,很多人第一印象是房産中介,專門負責新房、二手房買賣、以及租房等業務。

奔波在一線城市的人,想必都經曆過找房的辛酸(北漂的我默默地路過),不通過中介,想找到一個合适的小窩?不存在的。。。社群駐守、客戶介紹、網絡拓客、花錢買房源資訊,對于中介來說,這些簡直都是輕車熟路,房源哪裡逃!更可怕的是,前一秒是獨家,下一秒就是千百家。

這裡,中介是對象的通信中心。當房東需要與租客通信時,他們之間不會直接互動,而是通過中介将消息發送給目标對象。

建立抽象中介者

由于中介需要和所有參與者打交道,是以它除了注冊參與者之外,還需要将發送者的消息傳遞出去:

// mediator.h
#pragma once

#include "colleague.h"
#include <list>

class IColleague;

// 抽象中介者
class IMediator
{
public:
    // 注冊參與者
    virtual void registerColleague(IColleague* colleague) { m_colleagues.emplace_back(colleague); }
    const std::list<IColleague*>& getColleagues() const { return m_colleagues; }

    // 将發送者的消息發送給所有參與者
    virtual void distributeMessage(const IColleague* sender, const std::string& message) const = 0;

private:
    std::list<IColleague*> m_colleagues;
};           

建立具體中介者

具體中介者的職責是周遊所有的參與者,将發送者的消息通知到每一個人:

// concrete_mediator.h
#ifndef CONCRETE_MEDIATOR_H
#define CONCRETE_MEDIATOR_H

#include "mediator.h"

// 具體中介者
class ConcreteMediator : public IMediator
{
public:
    // 将發送者的消息發送給所有參與者(但不包括發送者自己)
    virtual void distributeMessage(const IColleague* sender, const std::string& message) const override {
        for (const IColleague* c : getColleagues())
            if (c != sender)  // 不要将消息發送給自己
                c->receiveMessage(sender, message);
    }
};

#endif // CONCRETE_MEDIATOR_H           

注意: 這裡需要添加限制

c != sender

,防止将消息回傳給發送者自己。

建立抽象同僚

由于房東和租客均由同僚類表示,是以既需要(房東)發送消息,又需要(租客)接收消息:

// colleague.h
#pragma once

#include "mediator.h"
#include <string>

class IMediator;

// 抽象同僚類
class IColleague
{
public:
    IColleague(const std::string& name) : m_strName (name) {}
    std::string getName() const { return m_strName; }

    // 通過中介者,将自己的消息釋出出去
    virtual void sendMessage(const IMediator& mediator, const std::string& message) const = 0;
    // 接收來自發送者的消息
    virtual void receiveMessage(const IColleague* sender, const std::string& message) const = 0;

private:
    std::string m_strName;
};           

建立具體同僚

在内部,具體的消息發送由中介者完成:

// concrete_colleague.h
#ifndef CONCRETE_COLLEAGUE_H
#define CONCRETE_COLLEAGUE_H

#include "colleague.h"
#include <iostream>

// 具體同僚類
class ConcreteColleague : public IColleague
{
public:
    using IColleague::IColleague;

    // 通過中介者,将自己的消息釋出出去
    virtual void sendMessage(const IMediator& mediator, const std::string& message) const override {
        mediator.distributeMessage(this, message);
    }

private:
    // 接收來自發送者的消息
    virtual void receiveMessage(const IColleague* sender, const std::string& message) const override {
        std::cout << getName() << " received the message from "
                  << sender->getName() << ": " << message << std::endl;
    }
};

#endif // CONCRETE_COLLEAGUE_H           

建立用戶端

找房啦!一旦房東将房子挂出去,中介便會通知所有需要租房的人:

// main.cpp
#include "concrete_colleague.h"
#include "concrete_mediator.h"

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif

int main()
{
    // 房東
    IColleague *landlord = new ConcreteColleague("Tom");

    // 租客
    IColleague *jerry = new ConcreteColleague("Jerry");
    IColleague *tuffy = new ConcreteColleague("Tuffy");

    // 中介者 - 添加租客
    ConcreteMediator mediator;
    mediator.registerColleague(jerry);
    mediator.registerColleague(tuffy);

    // 房東通過中介将消息發送出去
    landlord->sendMessage(mediator, "Xi'erqi, two bedroom house, 6000/month.");

    SAFE_DELETE(jerry);
    SAFE_DELETE(tuffy);

    getchar();

    return 0;
}           

輸出如下:

Jerry received the message from Tom: Xi’erqi, two bedroom house, 6000/month.

Tuffy received the message from Tom: Xi’erqi, two bedroom house, 6000/month.

繼續閱讀