本記事では、GoF(Gang of Four)が提唱した23のデザインパターンの一つである「Mediatorパターン」について解説します。
Mediatorパターンは、オブジェクト同士の複雑な相互作用を整理し、コードのメンテナンス性を高めるためのパターンです。
この記事では、Mediatorパターンの概要、使い方、そしてJava、C++、C#での実装例を紹介します。
Mediatorパターンとは
Mediatorパターンは、複数のオブジェクトがお互いに直接通信する代わりに、Mediator(仲介者)を介して相互作用することで、オブジェクト間の依存関係を緩和するパターンです。
これにより、システムの柔軟性と保守性が向上し、変更が必要な箇所を少なくすることができます。
Mediatorパターンの目的
Mediatorパターンの主な目的は、オブジェクト間の複雑な相互作用を一元化し、それぞれのオブジェクトが独立して機能できるようにすることです。
これにより、システム全体がよりモジュール化され、管理しやすくなります。
Mediatorパターンが適用されるケース
Mediatorパターンは、複数のコンポーネントが相互に通信し合う複雑なシステムで特に効果的です。
例えば、GUIコンポーネント間の相互作用や、複数のサーバー間での通信などに適用されます。
Mediatorパターンの使い方
Mediatorパターンを使うと、オブジェクト同士が直接依存せず、Mediatorを通じて通信するため、変更箇所が限定されます。
これにより、各コンポーネントが他のコンポーネントに依存せずに機能でき、柔軟な設計が可能となります。
Mediatorの役割
Mediatorパターンには、以下のような役割があります。
Mediatorパターン実装サンプル
ここでは、Mediatorパターンの実装サンプルをJava、C++、C#で紹介します。
各言語での基本的な実装を通じて、Mediatorパターンの具体的な使用方法を学びましょう。
JavaでのMediatorパターン実装
JavaでのMediatorパターンの実装例です。
// Mediatorインターフェース
public interface Mediator {
void notify(Component sender, String event);
}
// ConcreteMediatorクラス
public class ConcreteMediator implements Mediator {
private ComponentA componentA;
private ComponentB componentB;
public ConcreteMediator(ComponentA componentA, ComponentB componentB) {
this.componentA = componentA;
this.componentA.setMediator(this);
this.componentB = componentB;
this.componentB.setMediator(this);
}
@Override
public void notify(Component sender, String event) {
if (event.equals("A")) {
System.out.println("Component Aがイベントをトリガーしました。");
componentB.reactToA();
}
if (event.equals("B")) {
System.out.println("Component Bがイベントをトリガーしました。");
componentA.reactToB();
}
}
}
// ComponentAクラス
public class ComponentA extends Component {
public void doA() {
System.out.println("Component Aがアクションを実行しました。");
mediator.notify(this, "A");
}
public void reactToB() {
System.out.println("Component AがComponent Bのアクションに反応しました。");
}
}
// ComponentBクラス
public class ComponentB extends Component {
public void doB() {
System.out.println("Component Bがアクションを実行しました。");
mediator.notify(this, "B");
}
public void reactToA() {
System.out.println("Component BがComponent Aのアクションに反応しました。");
}
}
// メインクラス
public class Main {
public static void main(String[] args) {
ComponentA componentA = new ComponentA();
ComponentB componentB = new ComponentB();
ConcreteMediator mediator = new ConcreteMediator(componentA, componentB);
componentA.doA();
componentB.doB();
}
}
C++でのMediatorパターン実装
C++でのMediatorパターンの実装例です。
#include <iostream>
#include <string>
using namespace std;
// Mediatorクラス
class Mediator {
public:
virtual void notify(string event) = 0;
};
// Componentクラス
class Component {
protected:
Mediator* mediator;
public:
Component(Mediator* med) : mediator(med) {}
};
// ConcreteMediatorクラス
class ConcreteMediator : public Mediator {
private:
class ComponentA* componentA;
class ComponentB* componentB;
public:
void setComponentA(ComponentA* a) { componentA = a; }
void setComponentB(ComponentB* b) { componentB = b; }
void notify(string event) override {
if (event == "A") {
cout << "Component Aがイベントをトリガーしました。" << endl;
componentB->reactToA();
} else if (event == "B") {
cout << "Component Bがイベントをトリガーしました。" << endl;
componentA->reactToB();
}
}
};
// ComponentAクラス
class ComponentA : public Component {
public:
ComponentA(Mediator* med) : Component(med) {}
void doA() {
cout << "Component Aがアクションを実行しました。" << endl;
mediator->notify("A");
}
void reactToB() {
cout << "Component AがComponent Bのアクションに反応しました。" << endl;
}
};
// ComponentBクラス
class ComponentB : public Component {
public:
ComponentB(Mediator* med) : Component(med) {}
void doB() {
cout << "Component Bがアクションを実行しました。" << endl;
mediator->notify("B");
}
void reactToA() {
cout << "Component BがComponent Aのアクションに反応しました。" << endl;
}
};
// メインクラス
int main() {
ConcreteMediator mediator;
ComponentA componentA(&mediator);
ComponentB componentB(&mediator);
mediator.setComponentA(&componentA);
mediator.setComponentB(&componentB);
componentA.doA();
componentB.doB();
return 0;
}
C#でのMediatorパターン実装
C#でのMediatorパターンの実装例です。
using System;
// Mediatorインターフェース
public interface Mediator {
void Notify(object sender, string ev);
}
// ConcreteMediatorクラス
class ConcreteMediator : Mediator {
public ComponentA ComponentA { get; set; }
public ComponentB ComponentB { get; set; }
public void Notify(object sender, string ev) {
if (ev == "A") {
Console.WriteLine("Component Aがイベントをトリガーしました。");
ComponentB.ReactToA();
} else if (ev == "B") {
Console.WriteLine("Component Bがイベントをトリガーしました。");
ComponentA.ReactToB();
}
}
}
// Component基底クラス
abstract class Component {
protected Mediator mediator;
public Component(Mediator mediator) {
this.mediator = mediator;
}
}
// ComponentAクラス
class ComponentA : Component {
public ComponentA(Mediator mediator) : base(mediator) {}
public void DoA() {
Console.WriteLine("Component Aがアクションを実行しました。");
mediator.Notify(this, "A");
}
public void ReactToB() {
Console.WriteLine("Component AがComponent Bのアクションに反応しました。");
}
}
// ComponentBクラス
class ComponentB : Component {
public ComponentB(Mediator mediator) : base(mediator) {}
public void DoB() {
Console.WriteLine("Component Bがアクションを実行しました。");
mediator.Notify(this, "B");
}
public void ReactToA() {
Console.WriteLine("Component BがComponent Aのアクションに反応しました。");
}
}
// メインクラス
class Program {
static void Main(string[] args) {
ConcreteMediator mediator = new ConcreteMediator();
ComponentA componentA = new ComponentA(mediator);
ComponentB componentB = new ComponentB(mediator);
mediator.ComponentA = componentA;
mediator.ComponentB = componentB;
componentA.DoA();
componentB.DoB();
}
}
まとめ
Mediatorパターンは、オブジェクト同士の依存関係を緩和し、システム全体の柔軟性とメンテナンス性を向上させる非常に有効なデザインパターンです。
本記事では、Mediatorパターンの概要と目的、そしてJava、C++、C#での実装例を紹介しました。
複雑な相互作用を管理する必要がある場合には、このパターンを検討してみると良いでしょう。