Das Mediator Pattern ist ein Verhaltensmuster, das die Kommunikation zwischen Objekten erleichtert, indem es die direkte Interaktion zwischen ihnen vermeidet. Stattdessen erfolgt die Kommunikation über einen zentralen Vermittler. Dadurch wird die Kopplung zwischen den Objekten verringert und die Wartbarkeit verbessert.
Was ist das Mediator Pattern?
Das Mediator Pattern fördert die Entkopplung von Objekten, indem es einen Mediator einführt. Dieser fungiert als Vermittler, der die Kommunikation zwischen Objekten verwaltet. Anstatt direkt miteinander zu kommunizieren, senden die Objekte ihre Anfragen an den Mediator, der diese weiterleitet. So wird die Abhängigkeit zwischen den Objekten reduziert.
Komponenten des Mediator Patterns
Das Mediator Pattern besteht aus mehreren wichtigen Komponenten:
- Mediator: Ein Interface oder eine abstrakte Klasse, die die Kommunikation zwischen den Objekten definiert. Der Mediator empfängt Nachrichten von den Objekten und leitet diese weiter.
- ConcreteMediator: Eine konkrete Implementierung des Mediators. Sie verwaltet die Kommunikation zwischen den verschiedenen Objekten und übernimmt die Logik der Weiterleitung.
- Colleague: Objekte, die miteinander interagieren, aber über den Mediator kommunizieren. Sie sind vom Mediator abhängig, um Nachrichten zu empfangen und zu senden.
- ConcreteColleague: Eine konkrete Implementierung eines Objekts, das mit anderen Objekten über den Mediator kommuniziert.
Beispiel des Mediator Patterns in C++
Ein praktisches Beispiel des Mediator Patterns ist ein Chat-System, in dem Benutzer Nachrichten an den Mediator senden, der diese dann an andere Benutzer weiterleitet.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// Mediator: Abstrakte Klasse für den Mediator
class Mediator {
public:
virtual void sendMessage(const std::string& message, class Colleague* colleague) = 0;
virtual ~Mediator() = default;
};
// Colleague: Abstrakte Klasse für die Kollegen
class Colleague {
protected:
Mediator* mediator;
public:
Colleague(Mediator* mediator) : mediator(mediator) {}
virtual void receiveMessage(const std::string& message) = 0;
virtual ~Colleague() = default;
};
// ConcreteColleague: Konkrete Implementierung eines Kollegen
class ConcreteColleague : public Colleague {
private:
std::string name;
public:
ConcreteColleague(Mediator* mediator, const std::string& name)
: Colleague(mediator), name(name) {}
void sendMessage(const std::string& message) {
std::cout << name << " sends message: " << message << std::endl;
mediator->sendMessage(message, this);
}
void receiveMessage(const std::string& message) override {
std::cout << name << " receives message: " << message << std::endl;
}
};
// ConcreteMediator: Konkrete Implementierung des Mediators
class ConcreteMediator : public Mediator {
private:
std::vector<Colleague*> colleagues;
public:
void addColleague(Colleague* colleague) {
colleagues.push_back(colleague);
}
void sendMessage(const std::string& message, Colleague* colleague) override {
for (auto c : colleagues) {
// Senden Sie die Nachricht nur an die anderen Kollegen
if (c != colleague) {
c->receiveMessage(message);
}
}
}
};
// Client-Code
int main() {
// Erstellen des Mediators
ConcreteMediator mediator;
// Erstellen der Kollegen und Hinzufügen zum Mediator
ConcreteColleague colleague1(&mediator, "Alice");
ConcreteColleague colleague2(&mediator, "Bob");
mediator.addColleague(&colleague1);
mediator.addColleague(&colleague2);
// Senden von Nachrichten
colleague1.sendMessage("Hallo Bob, wie geht's?");
colleague2.sendMessage("Hallo Alice, mir geht's gut. Und dir?");
return 0;
}
Erklärung des C++-Beispiels
- Mediator: Die abstrakte Klasse
Mediator
definiert die MethodesendMessage()
, die vom konkreten Mediator implementiert wird. Diese Methode empfängt Nachrichten von den Kollegen und leitet sie weiter. - ConcreteMediator: Die Klasse
ConcreteMediator
ist die konkrete Implementierung des Mediators. Sie enthält eine Liste von Kollegen und stellt sicher, dass Nachrichten an alle anderen Kollegen weitergeleitet werden. - Colleague: Die abstrakte Klasse
Colleague
repräsentiert die Objekte, die miteinander kommunizieren müssen. Sie haben eine Referenz auf den Mediator, über den sie Nachrichten senden und empfangen. - ConcreteColleague: Die Klasse
ConcreteColleague
ist die konkrete Implementierung eines Kollegen. Sie kann Nachrichten an den Mediator senden und empfängt Nachrichten vom Mediator. - Client: Der Client erstellt den Mediator und die Kollegen und fügt sie dem Mediator hinzu. Die Kollegen können dann Nachrichten an den Mediator senden, der diese an die anderen Kollegen weiterleitet.
Vorteile des Mediator Patterns
- Entkopplung: Der Mediator reduziert die Kopplung zwischen den Objekten, da sie nur mit dem Mediator kommunizieren und nicht direkt miteinander.
- Vereinfachte Kommunikation: Die Kommunikation zwischen Objekten wird vereinfacht, da der Mediator als zentraler Punkt der Interaktion fungiert.
- Flexibilität: Neue Kollegen können leicht hinzugefügt werden, ohne dass Änderungen an den bestehenden Objekten vorgenommen werden müssen.
- Wartbarkeit: Da die Logik der Kommunikation in den Mediator verschoben wird, wird die Wartung des Systems vereinfacht. Änderungen an der Kommunikation betreffen nur den Mediator.
Nachteile des Mediator Patterns
- Komplexität: In großen Systemen kann der Mediator zu einer zentralen Stelle werden, die zu komplex ist und viele Verantwortlichkeiten übernimmt.
- Single Point of Failure: Der Mediator kann ein Single Point of Failure werden, da alle Kommunikationen durch ihn laufen.
- Leistungseinbußen: In Systemen mit vielen Kollegen kann der Mediator zu einem Bottleneck werden, da er jede Nachricht weiterleiten muss.
Fazit
Das Mediator Pattern ist ein leistungsfähiges Verhaltensmuster, das die Kommunikation zwischen Objekten verwaltet und entkoppelt. Es reduziert die Abhängigkeiten zwischen den Objekten und erleichtert so die Wartbarkeit und Erweiterbarkeit des Systems. Das Beispiel in C++ zeigt, wie das Muster die Kommunikation vereinfacht und die Kopplung zwischen den Objekten minimiert. Obwohl das Muster einige Nachteile hinsichtlich der Komplexität und Leistung haben kann, ist es besonders nützlich in Szenarien, in denen viele Objekte miteinander interagieren müssen, aber ihre Interaktionen zentral gesteuert werden sollen.
Zurück zur Liste aller Pattern: Liste der Design-Pattern