読者です 読者をやめる 読者になる 読者になる

【デザインパターン】Mediator

どんなもの?

  • 複雑に絡みあった複数のオブジェクト間の関係を、必ず仲介者を介して処理を行うようにすることで、単純かつ明快なインターフェースを提供する。
  • 管轄下にある複数のオブジェクトから問い合わせをうけ、判断を行い、管轄下のオブジェクトへ指示を出す

    どういうときに使う?

  • 複数のオブジェクトが相互に同期して機能するとき

    典型的な構成要素

  • Mediator
    • Colleagueからの相談を受け、それを元に判断を下し、Colleagueへ指示をだす。
    • 各Colleagueからの相談受付の窓口インターフェースを定義する。
    • 管轄下に置くColleagueを格納するためのインターフェースを定義する
  • ConcreteMediator
    • Mediatorのインターフェースを実装する。実際にColleaguを保持し、そこから相談を受け、判断を下し、それらに指示を出す。
  • Colleague
    • 他のColleaguを制御したい場合は、Mediatorに相談する。
    • Mediatorからの指示を受ける窓口インターフェースを定義する。
    • 自身が相談するMediatorを格納保持するための関数を定義する。
  • ConcreteColleague
    • Colleagueのインターフェースを実装する
  • Client

    コード

#include <iostream>
#include <string>
#include <map>

using namespace std;

class Mediator{
public:
  virtual void createColleague(void) = 0;
  virtual void colleagueModeChange(const string &name) = 0;
private:
};

class Colleague{
public:
  Colleague(Mediator *mediator):mediator(mediator){};
  virtual void modeChange(void) = 0;
  virtual void receiveModeChange(const string &name) = 0;
protected:
  Mediator *mediator;
};

class ConcreteColleagueA: public Colleague{
public:
  ConcreteColleagueA(Mediator *mediator):Colleague(mediator){};

  void modeChange(void){
    cout << "ConcreteColleagueA changes mode" << endl;
    mediator->colleagueModeChange("a");
  }

  void receiveModeChange(const string &name){
    cout << "ConcreteColleagueA receives mode change from " << name << endl;
  }
private:
};

class ConcreteColleagueB: public Colleague{
public:
  ConcreteColleagueB(Mediator *mediator):Colleague(mediator){};

  void modeChange(void){
    cout << "ConcreteColleagueB changes mode" << endl;
    mediator->colleagueModeChange("b");
  }

  void receiveModeChange(const string &name){
    cout << "ConcreteColleagueB receives mode change from " << name << endl;
  }
private:
};


class ConcreteColleagueC: public Colleague{
public:
  ConcreteColleagueC(Mediator *mediator):Colleague(mediator){};

  void modeChange(void){
    cout << "ConcreteColleagueC changes mode" << endl;
    mediator->colleagueModeChange("c");
  }

  void receiveModeChange(const string &name){
    cout << "ConcreteColleagueC receives mode change from " << name << endl;
  }
private:
};

class ConcreteMediator: public Mediator{
public:
  void createColleague(void){
    ConcreteColleagueA *a = new ConcreteColleagueA(this);
    colleague["a"] = a;
    ConcreteColleagueB *b = new ConcreteColleagueB(this);
    colleague["b"] = b;
    ConcreteColleagueC *c = new ConcreteColleagueC(this);
    colleague["c"] = c;
  }

  void colleagueModeChange(const string &name){
    for(auto it=colleague.begin();it!=colleague.end();++it){
      if(it->first!=name){
    it->second->receiveModeChange(name);
      }
    }
  }

  void changeMode(const string &name){
    for(auto it=colleague.begin();it!=colleague.end();++it){
      if(it->first==name){
    it->second->modeChange();
      }
    }
  }

private:
  map<string, Colleague*> colleague;
};

int main(){
  ConcreteMediator *mediator = new ConcreteMediator;
  mediator->createColleague();
  mediator->changeMode("a");
  mediator->changeMode("c");
  return 0;
}