#ifndef IMediator_h__#define IMediator_h__//-----------------------------------------------------------------------------------------------------------#include "IColleague.h"#include "InternalRequest.h"//-----------------------------------------------------------------------------------------------------------class IColleague;class IInternalRequest;//-----------------------------------------------------------------------------------------------------------// Базовый класс посредникclass IMediator{public: IMediator() { } virtual ~IMediator() { } virtual void RegisterColleague(IColleague* colleague) = 0; // Добавление коллеги virtual void UnregisterColleague(IColleague* colleague) = 0; // Удаление коллеги virtual void Send(IInternalRequest* cmd) = 0; // Отправка команды коллеге};//-----------------------------------------------------------------------------------------------------------#endif // IMediator_h__
#ifndef ColleaguesMediator_h__#define ColleaguesMediator_h__//-----------------------------------------------------------------------------------------------------------#include "IMediator.h"#include "IColleague.h"#include <list>//-----------------------------------------------------------------------------------------------------------class ColleaguesMediator : public IMediator{public: ColleaguesMediator() : IMediator() { } virtual ~ColleaguesMediator() { m_Colleagues.clear(); } // Добавление коллеги virtual void RegisterColleague(IColleague* colleague) override { m_Colleagues.push_back(colleague); } // Удаление коллеги virtual void UnregisterColleague(IColleague* colleague) override { auto it = std::find(m_Colleagues.begin(), m_Colleagues.end(), colleague); if (it != m_Colleagues.end()) m_Colleagues.erase(it); } // Отправка команды коллеге virtual void Send(IInternalRequest* cmd) override { // Поиск коллеги по указанному в команде получателю и отправка ему команды auto it = std::find(m_Colleagues.begin(), m_Colleagues.end(), cmd->GetReceiver()); if (it != m_Colleagues.end()) (*it)->RecvResponse(cmd); }private: std::list<IColleague*> m_Colleagues; // Список коллег};//-----------------------------------------------------------------------------------------------------------#endif // ColleaguesMediator_h
#ifndef IColleague_h__#define IColleague_h__//-----------------------------------------------------------------------------------------------------------#include "IMediator.h"#include "InternalRequest.h"#include <list>#include <memory>//-----------------------------------------------------------------------------------------------------------class IMediator;//-----------------------------------------------------------------------------------------------------------// Базовый класс коллега// Чтобы добавить нового коллегу, необходимо описать класс-наследник от класса IColleague// Переопределить чисто виртуальные методы SendRequest() и RecvResponse()// И реализовать отправку запросов и получение, разбор, обработку ответовclass IColleague{public: IColleague(IMediator* mediator) : m_Mediator(mediator) { } virtual ~IColleague() { m_RequestQueue.clear(); } virtual void SendRequest(IInternalRequest* cmd) = 0; // Отправка запроса через посредника virtual void RecvResponse(IInternalRequest* cmd) = 0; // Получение ответа через посредникаprotected: // Сохраняется ID каждого отправленного запроса, чтобы знать // Какие запросы были отправлены, и на какие ожидать ответы void AddRequestToQueue(int request_id) { m_RequestQueue.push_back(request_id); } // По получению ответа на запрос, ID запроса из списка удаляется void DelRequestFromQueue(int request_id) { auto it = std::find(m_RequestQueue.begin(), m_RequestQueue.end(), request_id); if (it != m_RequestQueue.end()) m_RequestQueue.erase(it); } // Проверка, ожидаем ли ответ по указанному ID bool IsRequestInQueue(int request_id) const { auto it = std::find(m_RequestQueue.begin(), m_RequestQueue.end(), request_id); if (it != m_RequestQueue.end()) return true; return false; }protected: IMediator* m_Mediator;private: std::list<int> m_RequestQueue; // Очередь запросов, содержащая ID запроса};//-----------------------------------------------------------------------------------------------------------#endif // IColleague_h__
#ifndef ColleagueA_h__#define ColleagueA_h__//-----------------------------------------------------------------------------------------------------------#include "IColleague.h"#include "InternalResponse.h"//-----------------------------------------------------------------------------------------------------------class ColleagueA : public IColleague{public: // В конструкторе добавляем посредника // В деструкторе отписываемся от него ColleagueA(IMediator* mediator) : IColleague(mediator) { } virtual ~ColleagueA() { m_Mediator->UnregisterColleague(this); } // Отправка запроса через посредника virtual void SendRequest(IInternalRequest* cmd) override { // Если отправляем запрос, помещаем ID запроса в список switch (cmd->GetTypeID()) { case TypeID::RequestA: AddRequestToQueue(cmd->GetID()); break; } cmd->SetSender(this); // Указываем себя в качестве отправителя m_Mediator->Send(cmd); // Отправляем команду посреднику } // Получение ответа через посредника virtual void RecvResponse(IInternalRequest* cmd) override { // Если запрос таким ID был отправлен и мы ожидаем ответ // С таким же ID, значит, обработаем, как ответ if (IsRequestInQueue(cmd->GetID())) { // Обработка ответа switch (cmd->GetTypeID()) { case TypeID::ResponseA: { auto c = dynamic_cast<ConcreteResponseA*>(cmd); auto p = c->GetParam(); // Получение параметра ответа ProcessResponseA(&p); // Какая-нибудь обработка break; } } // Ответ получили, ID из списка удаляем DelRequestFromQueue(cmd->GetID()); } else { // Обработка запроса } }private: // Какая-нибудь обработка void ProcessResponseA(int* value) { *value += 10; }};//-----------------------------------------------------------------------------------------------------------#endif // ColleagueA_h__
#ifndef ColleagueB_h__#define ColleagueB_h__//-----------------------------------------------------------------------------------------------------------#include "IColleague.h"//-----------------------------------------------------------------------------------------------------------class ColleagueB : public IColleague{public: // В конструкторе добавляем посредника // В деструкторе отписываемся от него ColleagueB(IMediator* mediator) : IColleague(mediator) { } virtual ~ColleagueB() { m_Mediator->UnregisterColleague(this); } // Отправка запроса через посредника virtual void SendRequest(IInternalRequest* cmd) override { /* switch (cmd->GetTypeID()) { case TypeID::RequestA: AddRequestToQueue(cmd->GetID()); break; } */ cmd->SetSender(this); // Указываем себя в качестве отправителя m_Mediator->Send(cmd); // Отправляем команду посреднику } // Получение ответа через посредника virtual void RecvResponse(IInternalRequest* cmd) override { /* if (IsRequestInQueue(cmd->GetID())) { // Обработка ответа // DelRequestFromQueue(cmd->GetID()); } else */ { // Обработка запроса switch (cmd->GetTypeID()) { case TypeID::RequestA: { auto c = dynamic_cast<ConcreteRequestA*>(cmd); auto p = c->GetParam(); // Получение параметра запроса ProcessCommandA(&p); // Какая-нибудь обработка // Формирование и отправка ответа на запрос // В ответе указываем получателя, который был отправителем запроса (return to sender) // ИД запроса и параметр ответа std::shared_ptr<IInternalRequest> response(new ConcreteResponseA(cmd->GetSender(), cmd->GetID(), p)); SendRequest(response.get()); // Отправляем ответ так же через посредника break; } } } }private: // Какая-нибудь обработка void ProcessCommandA(int* value) { *value *= 2; }};//-----------------------------------------------------------------------------------------------------------#endif // ColleagueB_h__
#ifndef InternalRequest_h__#define InternalRequest_h__//-----------------------------------------------------------------------------------------------------------#include "IColleague.h"#include <ctime>#include <cstdlib>//-----------------------------------------------------------------------------------------------------------class IColleague;//-----------------------------------------------------------------------------------------------------------// Тип запроса/ответа// Для добавления новой команды, достаточно добавить ИД типа для неё// Затем описать класс-наследник от IInternalRequest// Аналогично с добавлением нового ответаenum class TypeID{ RequestA = 0, // Запрос А ResponseA = 1 // Ответ А};//-----------------------------------------------------------------------------------------------------------// Базовый класс команды от которого наследуются классы запросов и ответовclass IInternalRequest{public: // Принимает получателя, ИД типа и ИД запроса // ИД типа - это поле TypeID, идентифицирующее команду или ответ на неё // ИД запроса - уникальный идентификатор конкретного запроса IInternalRequest(IColleague* reciever, TypeID type_id, int id = 0) : m_Sender(nullptr), m_Receiver(reciever), m_TypeID(type_id), m_ID(id) { if (!m_ID) { srand((unsigned)time(nullptr)); m_ID = rand(); } } virtual ~IInternalRequest() { m_Sender = m_Receiver = nullptr; } void SetSender(IColleague* sender) { m_Sender = sender; } void SetReceiver(IColleague* receiver) { m_Receiver = receiver; } IColleague* GetSender() const { return m_Sender; } IColleague* GetReceiver() const { return m_Receiver; } TypeID GetTypeID() const { return m_TypeID; } int GetID() const { return m_ID; }private: IColleague* m_Sender; IColleague* m_Receiver; TypeID m_TypeID; int m_ID;};//-----------------------------------------------------------------------------------------------------------
#ifndef InternalResponse_h__#define InternalResponse_h__//-----------------------------------------------------------------------------------------------------------#include "InternalRequest.h"//-----------------------------------------------------------------------------------------------------------// Ответ на команду Аclass ConcreteResponseA : public IInternalRequest{public: // На вход принимает получателя ответа, ИД ответа и параметр ответа // Устанавливает тип ответа ResponseA // Возможность установки ИД ответа обусловлена тем, что ИД запроса должен быть равен ИД ответа // И перед отправкой ответа, в качестве ИД передаётся ИД запроса // Таким образом появляется возможность сопоставить запрос и ответ ConcreteResponseA(IColleague* reciever, int id, int param) : IInternalRequest(reciever, TypeID::ResponseA, id), m_Param(param) { } virtual ~ConcreteResponseA() { } int GetParam() const { return m_Param; } private: int m_Param;};//-----------------------------------------------------------------------------------------------------------#endif // InternalResponse_h__
#include "ColleaguesMediator.h"#include "ColleagueA.h"#include "ColleagueB.h"#include <memory>//-----------------------------------------------------------------------------------------------------------int main(int argc, char* argv[]){ // Создание посредника std::shared_ptr<ColleaguesMediator> mediator(new ColleaguesMediator); // Создание коллег std::shared_ptr<ColleagueA> colleague_a(new ColleagueA(mediator.get())); std::shared_ptr<ColleagueB> colleague_b(new ColleagueB(mediator.get())); // Добавление коллег посреднику mediator->RegisterColleague(colleague_a.get()); mediator->RegisterColleague(colleague_b.get()); // Формирование и отправка запроса из коллеги А коллеге В std::shared_ptr<IInternalRequest> cmd(new ConcreteRequestA(colleague_b.get(), 12)); colleague_a->SendRequest(cmd.get()); return 0;}//-----------------------------------------------------------------------------------------------------------
C++ (Qt){ shared_ptr<Obj> o( new Obj( par1, par2 ) ); runFunc( o.get() );}
class IColleague{public: IColleague(IMediator* mediator) : m_Mediator(mediator) { } virtual ~IColleague() { m_RequestQueue.clear(); } virtual void SendRequest(IInternalRequest* cmd) = 0; // Отправка запроса через посредника
C++ (Qt)class SensorBase; class Manager{public: Manager() {} void addSensor( SensorBase *sensor ) { m_sensors.push_back( sensor ); } // Методы определяющие интерфейс взаимодействия // Сенсор отвалился void alarm( SensorBase *sensor ); // Изменилось значение сенсора void setValue( SensorBase *sensor, int value ); private: list<SensorBase*> m_sensors;} class SensorBase{public: SensorBase( Manager *manager ) : m_manager( manager ) {} protected: Manager *m_manager;} class Sensor : public SensorBase{public: Sensor( Manager *manager ) : SensorBase( manager ) {} void error() { m_manager->alarm( this ); } void valueChange() { m_manager->setValue( this, 100500 ); }}