ソフトウェア エンジニアリングでは、メディエーター パターンは、一連のオブジェクトがどのように相互作用するかをカプセル化するオブジェクトを定義します。このパターンは、プログラムの実行動作を変更できるため、 動作パターンと見なされます。
オブジェクト指向プログラミングでは、プログラムは多くのクラスで構成されることがよくあります。ビジネス ロジックと計算はこれらのクラスに分散されます。ただし、プログラムにクラスが追加されるにつれて、特にメンテナンスやリファクタリング中に、これらのクラス間の通信の問題がより複雑になる可能性があります。これにより、プログラムの読み取りとメンテナンスが困難になります。さらに、変更が他のいくつかのクラスのコードに影響を及ぼす可能性があるため、プログラムの変更が困難になる可能性があります。
メディエーター パターンでは、オブジェクト間の通信がメディエーター オブジェクト内にカプセル化されます。オブジェクトは互いに直接通信することはなくなり、メディエーターを介して通信するようになります。これにより、通信するオブジェクト間の依存関係が減り、結合が減ります。
概要
メディエーター[1]デザインパターンは、柔軟で再利用可能なオブジェクト指向ソフトウェア、つまり実装、変更、テスト、再利用が容易なオブジェクトを設計するために、繰り返し発生する設計上の問題を解決する方法を説明する、よく知られている23のデザインパターンの1つです。
メディエーターデザインパターンが解決できる問題[2]
- 相互作用するオブジェクトのセット間の密結合は避ける必要があります。
- オブジェクト セット間の相互作用を個別に変更できる必要があります。
相互作用するオブジェクトのセットを、直接アクセスして更新することで定義すると、オブジェクトが互いに密に結合され、オブジェクトから独立して (オブジェクトを変更せずに) 相互作用を変更することが不可能になるため、柔軟性がなくなります。また、オブジェクトの再利用が不可能になり、テストが困難になります。
密結合されたオブジェクトは、多くの異なるオブジェクトを参照し、それらについて認識しているため、実装、変更、テスト、再利用が困難です。
メディエーター設計パターンで記述されたソリューション
- オブジェクト セット間の相互作用をカプセル化する別の (メディエーター) オブジェクトを定義します。
- オブジェクトは、互いに直接対話するのではなく、メディエーター オブジェクトに対話を委任します。
オブジェクトは、相互作用を制御および調整するメディエーター オブジェクトを介して間接的に相互作用します。
これにより、オブジェクトは疎結合になります。オブジェクトは、メディエータ オブジェクトのみを参照し、認識しますが、互いの明示的な知識はありません。
下記の UML クラス図とシーケンス図も参照してください。
意味
メディエーター パターンの本質は、「一連のオブジェクトがどのように相互作用するかをカプセル化するオブジェクトを定義する」ことです。オブジェクトが互いに明示的に参照しないようにすることで疎結合を促進し、相互作用を独立して変更できるようにします。[3] [4]クライアント クラスは、メディエーターを使用して他のクライアントにメッセージを送信したり、メディエーター クラスのイベントを介して他のクライアントからメッセージを受信したりできます。
構造
UML クラス図とシーケンス図

上記のUML クラス図では、クラスColleague1とColleague2クラスは直接参照 (および更新) しません。代わりに、Mediator相互作用を制御および調整するための共通インターフェイス ( mediate()) を参照します。これにより、相互作用の実行方法に関して、クラスとクラスは互いに独立しています。クラスは、とクラスMediator1間の相互作用を実装します。
Colleague1Colleague2
UMLシーケンス図は、実行 時の相互作用を示します。この例では、オブジェクトがオブジェクト間の相互作用を仲介 (制御および調整) します。
Mediator1Colleague1Colleague2
Colleague1が と対話したい場合Colleague2(たとえば、状態を更新/同期するため)、 はオブジェクトに対して をColleague1呼び出し、 は から変更されたデータを取得し、に対して を実行します。
mediate(this)Mediator1Colleague1action2()Colleague2
その後、
オブジェクトに対して をColleague2呼び出し、オブジェクトから変更されたデータを取得してを実行します。
mediate(this)Mediator1Colleague2action1()Colleague1
クラス図

- 参加者
メディエーター-同僚オブジェクト 間の通信のためのインターフェースを定義します
ConcreteMediator - メディエーター インターフェイスを実装し、Colleagueオブジェクト間の通信を調整します。相互通信に関する すべてのColleagueとその目的を認識します。
同僚-メディエータを介して他の同僚と通信するためのインターフェースを定義します
ConcreteColleague - Colleague インターフェースを実装し、Mediatorを通じて他のColleagueと通信します。
例
C#
メディエーター パターンは、コンポーネントが疎結合であることを保証します。つまり、コンポーネントは明示的に互いを呼び出すのではなく、メディエーターへの呼び出しを通じて呼び出されます。次の例では、メディエーターはすべてのコンポーネントを登録し、それらの SetState メソッドを呼び出します。
インターフェイスIComponent { void SetState (オブジェクト状態); }
クラスComponent1 : IComponent {内部void SetState (オブジェクト状態) {新しいNotImplementedException ()をスローします。 } }
クラスComponent2 : IComponent {内部void SetState (オブジェクト状態) {新しいNotImplementedException ()をスローします。 } }
// 共通タスクを仲介します
class Mediator { internal IComponent Component1 { get ; set ; } internal IComponent Component2 { get ; set ; }
内部void ChangeState (オブジェクト状態) { this.Component1.SetState (状態) ; this.Component2.SetState (状態) ; } }
チャット ルームでは、メディエーター パターン、つまり、他のクライアントの 1 つがアクションを実行するたびに (チャット ルームの場合は各人がメッセージを送信するたびに)、多数の「クライアント」がそれぞれメッセージを受信するシステムを使用できます。実際には、チャット ルームでメディエーター パターンを使用するのは、リモート処理で使用する場合のみ実用的です。生のソケットを使用すると、デリゲート コールバック(Mediator クラスの MessageReceived イベントにサブスクライブしたユーザー)は使用できません。
パブリックデリゲートvoid MessageReceivedEventHandler (文字列メッセージ、文字列送信者);
パブリッククラスMediator {パブリックイベントMessageReceivedEventHandler MessageReceived ;
public void Send (文字列メッセージ、文字列送信者) { if ( MessageReceived ! = null ) { Console.WriteLine ( "'{0}' を {1} から送信しています" 、メッセージ、送信者); MessageReceived (メッセージ、送信者); } } }
パブリッククラスPerson {プライベートMediator _mediator ;
パブリック文字列Name { get ; set ; }
public Person ( Mediator mediator 、string name ) { Name = name ; _mediator = mediator ; _mediator . MessageReceived += new MessageReceivedEventHandler ( Receive ); }
private void Receive ( string message , string sender ) { if ( sender != Name ) Console.WriteLine ( "{0}は{2} から '{1}' を受信しました" , Name , message , sender ) ; }
パブリックvoid Send (文字列メッセージ) { _mediator.Send (メッセージ、名前) ; } }
ジャワ
次の例では、Mediatorオブジェクトが複数のオブジェクトの値を制御しStorage、ユーザー コードがメディエーターを介して格納された値にアクセスするように強制します。ストレージ オブジェクトが、その値が変更されたことを示すイベントを発行する場合、notifyObserversオブザーバーのリスト (オブザーバー パターンを使用して実装) を制御するメディエーター オブジェクトにも戻ります (メソッド経由)。
java.util.HashMapをインポートします。java.util.Optionalをインポートします。java.util.concurrent.CopyOnWriteArrayListをインポートします。java.util.function.Consumerをインポートします。
クラス Storage < T > { T value ; T getValue () {戻り値; } void setValue ( Mediator < T > mediator 、String storageName 、T value ) { this . value = value ; mediator . notificationObservers ( storageName ); } }
class Mediator < T > { private final HashMap < String , Storage < T >> storageMap = new HashMap < > (); private final CopyOnWriteArrayList < Consumer < String >> observers = new CopyOnWriteArrayList < > (); public void setValue ( String storageName , T value ) { Storage storage = storageMap.computeIfAbsent ( storageName , name - > new Storage <> ()) ; storage.setValue ( this , storageName , value ) ; } public Optional < T > getValue ( String storageName ) { return Optional.ofNullable ( storageMap.get ( storageName ) ) . map ( Storage :: getValue ) ; } public void addObserver ( String storageName , Runnable observer ) { observers.add ( eventName - > { if ( eventName.equals ( storageName ) ) { observer.run ( ) ; } } ) ; } void notificationObservers ( String eventName ) { observers.forEach ( observer - > observer.accept ( eventName ) ) ; } }
パブリッククラスMediatorDemo { public static void main ( String [] args ) { Mediator < Integer > mediator = new Mediator <> (); mediator . setValue ( "bob" , 20 ); mediator . setValue ( "alice" , 24 ); mediator . getValue ( "alice" ). ifPresent ( age -> System . out . println ( "alice の年齢: " + age )); mediator . addObserver ( "bob" , () -> { System . out . println ( "bob の新しい年齢: " + mediator . getValue ( "bob" ). orElseThrow ( RuntimeException :: new )); }); mediator . setValue ( "bob" , 21 ); } }
参照
- データ仲介
- デザインパターン、コンピュータサイエンスにおけるデザインパターンの研究のきっかけとなった書籍[要出典]
- ソフトウェア設計パターン、ソフトウェア設計における一般的な問題に対する標準的な解決策
参考文献
- ^ Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides (1994)。デザインパターン: 再利用可能なオブジェクト指向ソフトウェアの要素。Addison Wesley。pp. 273ff。ISBN 0-201-63361-2。
{{cite book}}: CS1 maint: 複数の名前: 著者リスト (リンク) - ^ Franke, Günther. 「The Mediator design pattern - Problem, Solution, and Applicability」w3sDesign . 2017-08-12閲覧。
- ^ ガンマ、エリック、ヘルム、リチャード、ジョンソン、ラルフ、ブリシデス、ジョン(1994)。デザインパターン。アディソン・ウェズリー。ISBN 0-201-63361-2。
- ^ 「メディエーター デザインパターン」。SourceMaking 。
- ^ Franke, Günther. 「The Mediator design pattern - Structure and Collaboration」. w3sDesign . 2017-08-12閲覧。
外部リンク
- Kaiser, Bodo (2012-09-21)。「メディエーター パターンの使用は推奨されますか?」。Stack Overflow。
