wake-up-neo.com

Mediator Vs Observer Objektorientierte Entwurfsmuster

Ich habe die Gang Of Four gelesen, um einige meiner Probleme zu lösen, und bin auf das Mediator -Muster gestoßen.

Ich hatte früher Observer in meinen Projekten verwendet, um eine GUI-Anwendung zu erstellen. Ich bin etwas verwirrt, da ich keinen großen Unterschied zwischen den beiden finde. Ich habe nach dem Unterschied gesucht, konnte aber keine passende Antwort für meine Anfrage finden.

Könnte mir jemand helfen, zwischen den beiden zu unterscheiden, mit einem guten Beispiel, das die beiden klar abgrenzt?

81
Fooo

Das Observer-Muster: Definiert eine Eins-zu-Viele-Abhängigkeit zwischen Objekten. Wenn ein Objekt seinen Status ändert, werden alle abhängigen Objekte benachrichtigt und automatisch aktualisiert. 

Das Mediator-Muster: Definieren Sie ein Objekt, das die Interaktion einer Objektgruppe kapselt. Mediator fördert die lose Kopplung, indem Objekte explizit auf einander verweisen, und Sie können deren Interaktion unabhängig voneinander variieren. 

Quelle: dofactory

Beispiel:

Das Beobachtermuster: Klasse A kann mit null oder mehr Beobachtern vom Typ O registriert sein. Wenn etwas in A geändert wird, benachrichtigt es alle Beobachter.

Das Vermittler-Muster: Sie haben eine Anzahl von Instanzen der Klasse X (oder vielleicht sogar mehrere verschiedene Typen: X, Y & Z), und sie möchten miteinander kommunizieren (aber Sie möchten nicht, dass jeder explizit ist) Verweise auf einander), so erstellen Sie eine Mediator-Klasse M. Jede Instanz von X hat eine Referenz auf eine gemeinsam genutzte Instanz von M, über die sie mit den anderen Instanzen von X (oder X, Y und Z) kommunizieren kann.

94
cdc

In dem ursprünglichen Buch, das die Begriffe Observer und Mediator, Design Patterns, Elemente wiederverwendbarer objektorientierter Software geprägt hat, heißt es, dass das Mediator-Pattern mithilfe des Observer-Patterns implementiert werden kann. Es kann jedoch auch implementiert werden, indem Kollegen (die in etwa dem Betreff des Observer-Musters entsprechen) einen Verweis auf eine Mediator-Klasse oder eine Mediator-Schnittstelle haben.

Es gibt viele Fälle, in denen Sie das Observer-Muster verwenden möchten. Der Schlüssel ist, dass ein Objekt nicht wissen sollte, was andere Objekte im Status beobachten.

Der Mediator ist etwas genauer, er vermeidet die direkte Kommunikation der Klassen, stattdessen durch einen Mediator. Dies hilft dem Prinzip der Einzelverantwortung, da die Kommunikation in eine Klasse verlagert werden kann, die nur die Kommunikation abwickelt.

Ein klassisches Mediator-Beispiel befindet sich in einer grafischen Benutzeroberfläche, bei der der naive Ansatz dazu führen könnte, dass auf einem Schaltflächenklickereignis Code angezeigt wird, der besagt, dass "Wenn das Foo-Bedienfeld deaktiviert ist und das Balkenbedienfeld mit einem Etikett versehen ist" Ansonsten fahren Sie fort ", wo es mit dem Mediator-Muster sagen könnte:" Ich bin nur ein Knopf und habe kein irdisches Geschäft, das über das Foo-Panel und das Label auf dem Bar-Panel Bescheid weiß. Ich werde meinen Mediator fragen, ob er den Server anruft ist jetzt in Ordnung. "

Oder wenn der Mediator mit dem Observer-Muster implementiert wird, würde der Button sagen: "Hey, Beobachter (die den Mediator einschließen würden), mein Zustand hat sich geändert (jemand hat mich angeklickt). Tun Sie etwas dagegen". In meinem Beispiel ist dies wahrscheinlich weniger sinnvoll, als den Mediator direkt zu referenzieren. In vielen Fällen wäre jedoch die Verwendung des Observer-Musters zur Implementierung von Mediator sinnvoll, und der Unterschied zwischen Observer und Mediator wäre eher eine Absicht als ein Unterschied im Code selbst.

31
psr

Beobachter

1. Ohne

  • Client1: Hey Betreff, wann ändern Sie?

  • Client2: Wann haben Sie Betreff geändert? Das habe ich nicht bemerkt!

  • Client3: Ich weiß, dass sich Subject geändert hat.

2. Mit

  • Clients sind stumm.
  • Etwas später ...
  • Betreff: Sehr geehrte Kunden, ich habe mich geändert!

Vermittler

1. Ohne

  • Client1: Hey Taxi1, bringen Sie mich wohin.
  • Client2: Hey Taxi1, bring mir was wohin.
  • Client1: Hey Taxi2, bringen Sie mich wohin.
  • Client2: Hey Taxi2, bringen Sie mich wohin.

2. Mit

  • Client1: Hey TaxiCenter, bitte bringen Sie mir ein Taxi.
  • Client2: Hey TaxiCenter, bitte bringen Sie mir ein Taxi.
29
Trix

Diese Muster werden in verschiedenen Situationen verwendet: 

Das Mediator-Muster wird verwendet, wenn Sie zwei Subsysteme mit einer gewissen Abhängigkeit haben und eines davon für eine Änderung fällig ist. Da Sie möglicherweise nicht das System ändern möchten, das von dem anderen abhängig ist, möchten Sie möglicherweise einen Mediator einführen, der dies tun wird entkoppeln die Abhängigkeit zwischen ihnen. Auf diese Weise müssen Sie, wenn sich eines der Subsysteme ändert, den Mediator aktualisieren.

Das Beobachtermuster wird verwendet, wenn eine Klasse anderen Klassen die Registrierung zulässt und Benachrichtigungen zu Ereignissen empfängt, z. G. ButtonListener etc.

Beide Muster erlauben eine geringere Kopplung, sind jedoch recht unterschiedlich.

13
uzilan

Obwohl beide für organisierte Informationen über Zustandsänderungen verwendet werden, unterscheiden sie sich strukturell und semantisch von der IMO. 

Observer wird verwendet, um eine Zustandsänderung eines bestimmten Objekts vom Objekt selbst zu senden. Die Änderung geschieht also in dem zentralen Objekt, das auch für die Signalisierung verantwortlich ist. In Mediator kann es jedoch zu Statusänderungen in jedem Objekt kommen, aber es wird von einem Mediator gesendet. Es gibt also einen Unterschied im Fluss. Ich denke jedoch nicht, dass dies unser Codeverhalten beeinflusst. Wir können das eine oder andere verwenden, um dasselbe Verhalten zu erreichen. Andererseits kann sich dieser Unterschied auf das konzeptuelle Verständnis des Codes auswirken. 

Siehe, der Hauptzweck von Mustern besteht eher darin, eine gemeinsame Sprache zwischen Entwicklern zu erstellen. Wenn ich also einen Vermittler sehe, verstehe ich persönlich mehrere Elemente, die versuchen, über einen einzelnen Broker/Hub zu kommunizieren, um das Kommunikationsrauschen zu reduzieren (oder SRP zu fördern), und jedes Objekt ist gleichermaßen wichtig für die Signalisierung einer Zustandsänderung. Denken Sie beispielsweise an mehrere Flugzeuge, die sich einem Flughafen nähern. Jeder sollte über den Pylon (Vermittler) kommunizieren, anstatt miteinander zu kommunizieren. (Denken Sie an 1000 Flugzeuge, die bei der Landung miteinander kommunizieren)

Wenn ich jedoch einen Beobachter sehe, bedeutet das, dass es einige Statusänderungen gibt, die mich interessieren könnten, und sollte sich registrieren/abonnieren, um bestimmte Statusänderungen zu hören. Es gibt ein zentrales Objekt, das für die Signalisierung von Zustandsänderungen verantwortlich ist. Wenn ich mich beispielsweise für einen bestimmten Flughafen auf dem Weg von A nach B interessiere, kann ich mich dort registrieren, um einige Ereignisse zu sehen, die gesendet werden, etwa wenn es eine leere Landebahn gibt oder ähnliches. 

Hoffe es ist klar.

4
stdout

@cdc hat den Unterschied in der Absicht hervorragend erklärt. 

Ich werde noch ein paar Infos dazu hinzufügen.

Observer : Ermöglicht die Benachrichtigung eines Ereignisses in einem Objekt an verschiedene Objektgruppen (Instanzen verschiedener Klassen)

Mediator : Zentralisiert die Kommunikation zwischen Objektgruppen, die aus einer bestimmten Klasse erstellt wurden. 

Struktur des Mediatormusters aus dofactory :

 enter image description here

Mediator: Definiert eine Schnittstelle für die Kommunikation zwischen Kollegen.

Kollege: Ist eine abstrakte Klasse, die die Ereignisse definiert, die zwischen Kollegen kommuniziert werden sollen

ConcreteMediator: Implementiert kooperatives Verhalten, indem Kollege Objekte koordiniert und seine Kollegen gepflegt werden

ConcreteColleague: Implementiert die Benachrichtigungsvorgänge, die über Mediator empfangen wurden, die von anderen Kollegen generiert wurden.

Ein reales Beispiel:

Sie pflegen ein Computernetzwerk in der Mesh -Topologie. Wenn ein neuer Computer hinzugefügt wird oder ein vorhandener Computer entfernt wird, sollten alle anderen Computer in diesem Netzwerk über diese beiden Ereignisse Bescheid wissen. 

Mal sehen, wie das Mediator-Muster darin passt.

Code-Auszug:

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);
    }
}

ausgabe:

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

Erläuterung:

  1. Eagle wird zunächst durch ein register-Ereignis zum Netzwerk hinzugefügt. Keine Benachrichtigungen an andere Kollegen, da Eagle der erste ist. 
  2. Wenn Ostrich zum Netzwerk hinzugefügt wird, wird Eagle benachrichtigt: Zeile 1 der Ausgabe wird jetzt gerendert.
  3. Wenn Pinguin zum Netzwerk hinzugefügt wird, wurden sowohl Eagle als auch Ostrich benachrichtigt: Zeile 2 und Zeile 3 der Ausgabe werden jetzt gerendert.
  4. Wenn Eagle das Netzwerk durch Aufheben der Registrierung verlassen hat, wurden sowohl Ostrich als auch Penguin benachrichtigt. Die Zeilen 4 und 5 der Ausgabe werden jetzt gerendert.
4
Ravindra babu

Gehen wir von einem Beispiel aus: Sie möchten zwei Anwendungen erstellen:

  1. Chat-Anwendung.
  2. Notfall-Rettungsdienst-Anwendung.

vermittler

Beim Erstellen der Chat-Anwendung wählen Sie das Designmuster mediator aus.

  • Die Personen können dem Chat zu einem bestimmten Zeitpunkt beitreten und diesen verlassen, so dass es keinen Sinn macht, den direkten Kontakt zwischen zwei Chatern zu halten.
  • Wir müssen immer noch eine Kommunikation zwischen zwei Personen ermöglichen und ihnen ein Gespräch ermöglichen. 

Warum bevorzugen wir die mediator? Schauen Sie sich einfach seine Definition an:

Bei dem Mediator-Muster erfolgt die Kommunikation zwischen Objekten in einem Mediator-Objekt gekapselt. Objekte kommunizieren nicht mehr direkt miteinander, sondern kommunizieren stattdessen über die Vermittler. Dies reduziert die Abhängigkeiten zwischen kommunizierenden Objekten dadurch wird die Kopplung reduziert.

Wie funktioniert die Magie? Zuerst erstellen wir den Chat-Vermittler und lassen die Personenobjekte registrieren, so dass er mit jeder einzelnen Person eine direkte Verbindung hat (die Person kann eine Nachricht über den Chat-Vermittler senden, da sie darauf Zugriff hat, und der Chat-Vermittler greift zu.) die empfangene Methode des Personenobjekts, da er auch Zugriff darauf hat)

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);

beobachter

Beim Erstellen der 911-Aufrufanwendung wählen Sie das Entwurfsmuster observer aus.

  • Jedes Objekt des Rettungswagens observer möchte im Notfall informiert werden, damit er die Adresse steuern und Hilfe geben kann. 
  • Der Notfalloperator observable verweist auf jeden Krankenwagen observers und benachrichtigt sie, wenn Hilfe benötigt wird (oder ein Ereignis generiert wird).

Warum bevorzugen wir die observer? Schauen Sie sich einfach seine Definition an:

Ein Objekt, das als Betreff bezeichnet wird, verwaltet eine Liste seiner abhängigen Objekte Beobachter genannt, und benachrichtigt sie automatisch über jeden Zustand Änderungen, normalerweise durch Aufrufen einer ihrer Methoden.

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);

Die Unterschiede:

  1. Der Chat mediator hat eine bidirektionale Kommunikation zwischen den Personenobjekten (Senden und Empfangen), während der Bediener observable nur eine Einbahnverbindung hat (er weist den Krankenwagen observer an, zu fahren und zu beenden).
  2. Der Chat mediator kann die Personenobjekte zwischen sich interagieren lassen (auch wenn es keine direkte Kommunikation ist), die Krankenwagen observers registrieren sich nur bei den Operatoren observable Ereignissen.
  3. Jedes Personenobjekt hat einen Verweis auf den Chat mediator, und auch der Chat mediator verweist auf alle Personen. Während der Rettungswagen observer nicht auf den Operator observable verweist, bleibt nur der Operator observable auf jeden Rettungswagen observer verweisen.
1
Shahar Shokrani

How Über diese Erklärung Technisch gesehen sind Observer und Mediator identisch und werden verwendet, um entkoppelte Möglichkeiten für die Komponentenkommunikation zu bieten. Die Verwendung ist jedoch unterschiedlich.

Während obeserverbenachrichtigtsubscribe -Komponenten über Statusänderungen (z. B. Erstellung eines neuen Datenbanksatzes), können die mediator-Befehleregistrierten -Komponenten etwas unternehmen, um geschäftliche Angelegenheiten zu erledigen Logikablauf (Senden einer E-Mail an den Benutzer zum Zurücksetzen des Kennworts).

Beobachter

  • Benachrichtigung Verbraucher sind verpflichtet zu abonnieren, um Benachrichtigungen zu erhalten
  • Die Benachrichtigungsverarbeitung ist nicht Teil des Geschäftsablaufs

Vermittler

  • Explizite Registrierung erforderlich, um "Publisher" und "Consumer" zu verbinden
  • Die Benachrichtigungsverarbeitung ist Teil eines bestimmten Geschäftsablaufs
0