私はギャングオブフォーを読んでいますいくつかの問題を解決するためにて、Mediatorパターンに出くわしました。
以前使用していた 、プロジェクトでいくつかのGUIアプリケーションを作成するためにObserverを。この2つに大きな違いはないので、少し混乱しています。違いを見つけるために閲覧しましたが、私のクエリに対する適切な答えを見つけることができませんでした。
2人を明確に区別するいくつかの良い例で2人を区別するのに役立つ人がいますか?
私はギャングオブフォーを読んでいますいくつかの問題を解決するためにて、Mediatorパターンに出くわしました。
以前使用していた 、プロジェクトでいくつかのGUIアプリケーションを作成するためにObserverを。この2つに大きな違いはないので、少し混乱しています。違いを見つけるために閲覧しましたが、私のクエリに対する適切な答えを見つけることができませんでした。
2人を明確に区別するいくつかの良い例で2人を区別するのに役立つ人がいますか?
ChangeManager
するObserver
パターンのaの例を示して対処していますMediator
。見る; paginas.fe.up.pt/~aaguiar/as/gof/hires/pat5g.htm#samplecode
回答:
Observerパターン:オブジェクト間の1対多の依存関係を定義します。これにより、1つのオブジェクトの状態が変化すると、そのすべての依存オブジェクトが自動的に通知および更新されます。
Mediatorパターン:オブジェクトのセットがどのように相互作用するかをカプセル化するオブジェクトを定義します。Mediatorは、オブジェクトが相互に明示的に参照しないようにすることで疎結合を促進し、相互作用を個別に変化させることができます。
ソース:dofactory
例:
オブザーバーパターン:クラスAには、タイプOの0個以上のオブザーバーを登録できます。Aの何かが変更されると、すべてのオブザーバーに通知されます。
メディエーターパターン:クラスXのインスタンスがいくつかあり(または、いくつかの異なるタイプ:X、Y、Zでさえも)、お互いに通信したい(ただし、それぞれに明示的な参照を設定したくない) other)、メディエータークラスMを作成します。Xの各インスタンスには、Mの共有インスタンスへの参照があり、それを介してXの他のインスタンス(またはX、Y、Z)と通信できます。
ObserverとMediator、Design Patterns、Elements of Reusable Object-Oriented Softwareという用語を作り出したオリジナルの本してMediatorパターンを実装できると述べています。ただし、同僚(オブザーバーパターンのサブジェクトとほぼ同等)にMediatorクラスまたはMediatorインターフェイスへの参照を持たせることで実装することもできます。
オブザーバーパターンを使用したい場合が多くありますが、それらの重要な点は、オブジェクトは他のオブジェクトがその状態を監視していることを知らないということです。
メディエーターはもう少し具体的です。クラスが直接メディエーターを介して通信することを避けます。これにより、通信を処理するクラスだけに通信をオフロードできるようになり、単一責任の原則が役立ちます。
古典的なMediatorの例はGUIにあり、単純なアプローチでは、ボタンクリックイベントで「Fooパネルが無効で、Barパネルに「日付を入力してください」というラベルが付いている場合は、サーバーを呼び出さない」というコードが表示される可能性があります。それ以外の場合は先に進んでください。メディエーターパターンを使用すると、「私は単なるボタンであり、Fooパネルとバーパネルのラベルを知っている地上のビジネスはないので、サーバーを呼び出すかどうかをメディエーターに尋ねます今は大丈夫です。」
または、メディエーターがオブザーバーパターンを使用して実装されている場合、ボタンには「ねえ、オブザーバー(メディエーターが含まれます)、私の状態が変更されました(誰かが私をクリックしました)。メディエーターを直接参照するよりもおそらく意味が少ない私の例では、多くの場合、オブザーバーパターンを使用してメディエーターを実装することは理にかなっており、オブザーバーとメディエーターの違いは、コード自体の違いよりも意図の1つです。
Client1:Hey Subject、いつ変更しますか?
Client2:件名をいつ変更しましたか?気づかなかった!
Client3:私は件名が変更されたことを知っています。
これらのパターンは、さまざまな状況で使用されます。
メディエーターパターンは、依存関係のある2つのサブシステムがあり、そのうちの1つが変更によるものである場合に使用されます。また、他のシステムに依存するシステムを変更したくないため、メディエーターを導入することもできます。それらの間の依存関係を切り離します。そうすれば、サブシステムの1つが変更されたときに、メディエーターを更新するだけで済みます。
オブザーバーパターンは、クラスが他のクラスを登録し、ButtonListenerなどのイベントの通知を受信できるようにする場合に使用されます。
これらのパターンはどちらも結合を少なくすることができますが、まったく異なります。
例を挙げましょう。2つのアプリケーションを作成するとします。
チャットアプリケーションを構築するには、mediator
デザインパターンを選択します。
なぜ私たちは好きmediator
ですか?その定義を見てください:
メディエーターパターンを使用すると、オブジェクト間の通信がメディエーターオブジェクト内にカプセル化されます。オブジェクトは互いに直接通信しなくなり、メディエーターを介して通信します。これにより、通信するオブジェクト間の依存関係が減少し、結合が減少します。
魔法はどのように機能しますか?最初に、チャットメディエーターを作成し、personsオブジェクトをそれに登録します。これにより、すべての個人と2方向の接続が確立されます(チャットメディエーターを使用してメッセージを送信できるため、チャットメディエーターがアクセスし、チャットメディエーターがアクセスします。 personオブジェクトの受け取ったメソッドにより、彼はそれにアクセスすることもできます)
function Person(name) {
let self = this;
this._name = name;
this._chat = null;
this._receive(from, message) {
console.log("{0}: '{1}'".format(from.name(), message));
}
this._send(to, message) {
this._chat.message(this, to, message);
}
return {
receive: (from, message) => { self._receive(from, message) },
send: (to, message) => { self._send(to, message) },
initChat: (chat) => { this._chat = chat; },
name: () => { return this._name; }
}
}
function ChatMediator() {
let self = this;
this._persons = [];
return {
message: function (from, to, message) {
if (self._persons.indexOf(to) > -1) {
self._persons[to].receive(from, message);
}
},
register: function (person) {
person.initChat(self);
self._persons.push(person);
}
unRegister: function (person) {
person.initChat(null);
delete self._persons[person.name()];
}
}
};
//Usage:
let chat = new ChatMediator();
let colton = new Person('Colton');
let ronan = new Person('Ronan');
chat.register(colton);
chat.register(ronan);
colton.send(colton, 'Hello there, nice to meet you');
ronan.send(ronan, 'Nice to meet you to');
colton.send(colton, 'Goodbye!');
chat.unRegister(colton);
911コールアプリケーションを構築するには、observer
デザインパターンを選択します。
observer
オブジェクトは、緊急事態が発生したときに通知を受けることを望んでいるので、住所を運転して手助けすることができます。observable
は、救急車のそれぞれの参照を維持observers
し、助けが必要な場合(またはイベントを生成する場合)に通知します。なぜ私たちは好きobserver
ですか?その定義を見てください:
サブジェクトと呼ばれるオブジェクトは、オブザーバーと呼ばれるその依存関係のリストを維持し、通常はメソッドの1つを呼び出すことによって、状態の変化を自動的に通知します。
function AmbulanceObserver(name) {
let self = this;
this._name = name;
this._send(address) {
console.log(this._name + ' has been sent to the address: ' + address);
}
return {
send: (address) => { self._send(address) },
name: () => { return this._name; }
}
}
function OperatorObservable() {
let self = this;
this._ambulances = [];
return {
send: function (ambulance, address) {
if (self._ambulances.indexOf(ambulance) > -1) {
self._ambulances[ambulance].send(address);
}
},
register: function (ambulance) {
self._ambulances.push(ambulance);
}
unRegister: function (ambulance) {
delete self._ambulances[ambulance.name()];
}
}
};
//Usage:
let operator = new OperatorObservable();
let amb111 = new AmbulanceObserver('111');
let amb112 = new AmbulanceObserver('112');
operator.register(amb111);
operator.register(amb112);
operator.send(amb111, '27010 La Sierra Lane Austin, MN 000');
operator.unRegister(amb111);
operator.send(amb112, '97011 La Sierra Lane Austin, BN 111');
operator.unRegister(amb112);
mediator
は、人物オブジェクト間の2方向の通信(送信と受信)を持ち、オペレーターobservable
は1方向の通信しかできません(救急車observer
に運転と終了を伝えます)。mediator
は、(直接の通信ではない場合でも)人のオブジェクトがそれらの間で相互作用するようにすることができ、救急車observers
はオペレーターのobservable
イベントに登録するだけです。mediator
でmediator
は、すべての人物への参照も保持されます。救急車observer
がobservable
オペレーターobservable
を参照しない場合、オペレーターのみがすべての救急車を参照しますobserver
。どちらも状態の変化を体系的に伝えるために使用されますが、構造的および意味的にIMOとは少し異なります。
オブザーバーは、オブジェクト自体から、特定のオブジェクトの状態変化をブロードキャストするために使用されます。したがって、変更は、それを通知する役割も果たす中央オブジェクトで発生します。ただし、メディエーターでは、状態の変化は任意のオブジェクトで発生する可能性がありますが、メディエーターからブロードキャストされます。そのため、フローに違いがあります。しかし、これがコードの動作に影響を与えるとは思いません。同じ振る舞いを達成するために、どちらかを使用できます。一方、この違いは、コードの概念的な理解に影響を与える可能性があります。
参照してください、パターンを使用する主な目的は、むしろ開発者間の共通言語を作成することです。したがって、メディエーターを見ると、単一のブローカー/ハブを介して通信して通信ノイズを減らす(またはSRPを促進する)ことを試みる複数の要素を個人的に理解しており、各オブジェクトは状態の変化を通知する機能を持つという点で同様に重要です。たとえば、空港に近づいている複数の航空機について考えてみましょう。それぞれが互いに通信するのではなく、パイロン(メディエーター)を介して通信する必要があります。(着陸時に1000機の航空機が互いに通信していると考えてください-混乱します)
ただし、オブザーバーを見ると、気になる可能性のあるいくつかの状態変化があり、特定の状態変化をリッスンするには登録/サブスクライブする必要があります。状態変化の通知を担当する中心的なオブジェクトがあります。たとえば、AからBに向かう途中の特定の空港を気にする場合は、その空港に登録して、空の滑走路があるかなどのブロードキャストイベントをキャッチできます。
それが明確であることを願っています。
@cdcは意図の違いをうまく説明しました。
その上にさらに情報を追加します。
オブザーバー:1つのオブジェクトのイベントを異なるオブジェクトのセット(異なるクラスのインスタンス)に通知できるようにします。
調停者:特定のクラスから作成されたオブジェクトのセット間の通信を集中化します。
dofactoryのMediatorパターンの構造:
Mediator:同僚間のコミュニケーションのためのインターフェースを定義します。
同僚:同僚間で通信されるイベントを定義する抽象クラスです
ConcreteMediator:同僚オブジェクトを調整することにより協調動作を実装し、その同僚を維持します
ConcreteColleague:他の同僚によって生成されたMediatorを介して受信した通知操作を実装します
実世界の例:
メッシュでコンピューターのネットワークを維持しているトポロジ。新しいコンピュータが追加された場合、または既存のコンピュータが削除された場合、そのネットワーク内の他のすべてのコンピュータはこれら2つのイベントを認識しているはずです。
Mediatorパターンがそれにどのように適合するかを見てみましょう。
コードスニペット:
import java.util.List;
import java.util.ArrayList;
/* Define the contract for communication between Colleagues.
Implementation is left to ConcreteMediator */
interface Mediator{
public void register(Colleague colleague);
public void unregister(Colleague colleague);
}
/* Define the contract for notification events from Mediator.
Implementation is left to ConcreteColleague
*/
abstract class Colleague{
private Mediator mediator;
private String name;
public Colleague(Mediator mediator,String name){
this.mediator = mediator;
this.name = name;
}
public String toString(){
return name;
}
public abstract void receiveRegisterNotification(Colleague colleague);
public abstract void receiveUnRegisterNotification(Colleague colleague);
}
/* Process notification event raised by other Colleague through Mediator.
*/
class ComputerColleague extends Colleague {
private Mediator mediator;
public ComputerColleague(Mediator mediator,String name){
super(mediator,name);
}
public void receiveRegisterNotification(Colleague colleague){
System.out.println("New Computer register event with name:"+colleague+
": received @"+this);
// Send further messages to this new Colleague from now onwards
}
public void receiveUnRegisterNotification(Colleague colleague){
System.out.println("Computer left unregister event with name:"+colleague+
":received @"+this);
// Do not send further messages to this Colleague from now onwards
}
}
/* Act as a central hub for communication between different Colleagues.
Notifies all Concrete Colleagues on occurrence of an event
*/
class NetworkMediator implements Mediator{
List<Colleague> colleagues = new ArrayList<Colleague>();
public NetworkMediator(){
}
public void register(Colleague colleague){
colleagues.add(colleague);
for (Colleague other : colleagues){
if ( other != colleague){
other.receiveRegisterNotification(colleague);
}
}
}
public void unregister(Colleague colleague){
colleagues.remove(colleague);
for (Colleague other : colleagues){
other.receiveUnRegisterNotification(colleague);
}
}
}
public class MediatorPatternDemo{
public static void main(String args[]){
Mediator mediator = new NetworkMediator();
ComputerColleague colleague1 = new ComputerColleague(mediator,"Eagle");
ComputerColleague colleague2 = new ComputerColleague(mediator,"Ostrich");
ComputerColleague colleague3 = new ComputerColleague(mediator,"Penguin");
mediator.register(colleague1);
mediator.register(colleague2);
mediator.register(colleague3);
mediator.unregister(colleague1);
}
}
出力:
New Computer register event with name:Ostrich: received @Eagle
New Computer register event with name:Penguin: received @Eagle
New Computer register event with name:Penguin: received @Ostrich
Computer left unregister event with name:Eagle:received @Ostrich
Computer left unregister event with name:Eagle:received @Penguin
説明:
方法この説明について技術的には、オブザーバーとメディエーターは同じであり、コンポーネント通信に分離された方法を提供するために使用されますが、使用方法は異なります。
obeserver
が サブスクライブしたコンポーネントに状態の変化(たとえば、新しいdbレコードの作成)を通知する間、登録されたmediator
コマンド コンポーネントをして、ビジネスロジックフローに関連する何かを実行します(パスワードのリセットのためにユーザーに電子メールを送信します)。
Programmers.StackExchange
は拒否されましたが、回答に興味があったため、同様の投稿を行いました。興味深い答えがいくつか見つかるかもしれません。:)