Python-Vermittlermuster

Das Mediator-Muster ist ein Verhaltensentwurfsmuster, das direkte Kommunikationsabhängigkeiten zwischen Objekten reduziert, indem ein Mediator-Objekt eingeführt wird. Stellen Sie sich einen Flughafen-Kontrollturm im wirklichen Leben vor – alle Flugzeuge kommunizieren nicht direkt miteinander, sondern koordinieren Starts, Landungen und Routen über den Kontrollturm, wodurch Chaos und Konflikte vermieden werden.

Wenn in der Softwareentwicklung komplexe Interaktionsbeziehungen zwischen mehreren Objekten bestehen, kann das Mediator-Muster diese Interaktionen im Mediator kapseln und dadurch die Kopplung zwischen Objekten reduzieren.

Kernidee

Die Kernidee des Mediator-Musters ist„Sprich nicht direkt; koordiniere über einen Mediator.“Es löst die Komplexität von Viele-zu-viele-Interaktionen zwischen Objekten und macht das System einfacher zu warten und zu erweitern.


Warum brauchen wir das Mediator-Muster?

Problemszenario

Angenommen, wir entwickeln ein Chatroom-System mit mehreren Benutzern, die sich gegenseitig Nachrichten senden müssen. Ohne einen Mediator könnte der Code so aussehen:

Beispiel

class User:
    def __init__(self, name):
        self.name = name
        self.other_users = []  # Muss alle anderen Benutzer kennen
   
    def send_message(self, message, to_user):
        print(f"{self.name} hat an {to_user.name} gesendet: {message}")
        to_user.receive_message(message, self)
   
    def receive_message(self, message, from_user):
        print(f{self.name} hat eine Nachricht von {from_user.name} erhalten: {message})

# Verwendungsbeispiel
user1 = User(Xiaoming)
user2 = User(Xiaohong)
user3 = User(Xiaogang)

# Jeder Benutzer muss alle anderen Benutzer kennen
user1.other_users = [user2, user3]
user2.other_users = [user1, user3]
user3.other_users = [user1, user2]

user1.send_message(Hallo!, user2)

Nachteile dieses Entwurfs:

  • Hohe Kopplung zwischen Objekten; jeder Benutzer muss alle anderen Benutzer kennen.
  • Das Hinzufügen eines neuen Benutzers erfordert die Änderung aller vorhandenen Benutzer.
  • Schwer zu warten; die Interaktionslogik ist über Objekte verstreut.

Lösung

Das Mediator-Muster löst dieses Problem durch die Einführung eines Chatraums (Mediator):

Beispiel

class ChatRoom:
    def __init__(self):
        self.users = {}
   
    def register_user(self, user):
        self.users[user.name] = user
        user.chat_room = self
   
    def send_message(self, message, from_user, to_user_name=Keine):
        if to_user_name:  # Privater Chat
            if to_user_name in self.users:
                self.users[to_user_name].receive_message(message, from_user)
        else:  # Gruppenchat
            for user_name, user in self.users.items():
                if user_name != from_user.name:
                    user.receive_message(message, from_user)

class User:
    def __init__(self, name):
        self.name = name
        self.chat_room = None
   
    def send_message(self, message, to_user_name=None):
        if self.chat_room:
            self.chat_room.send_message(message, self, to_user_name)
   
    def receive_message(self, message, from_user):
        print(f{self.name} hat eine Nachricht von {from_user.name} erhalten: {message})

# Verwendungsbeispiel
chat_room = ChatRoom()

user1 = User(Xiaoming)
user2 = User(Xiaohong)
user3 = User(Xiaogang)

chat_room.register_user(user1)
chat_room.register_user(user2)
chat_room.register_user(user3)

user1.send_message(Hallo zusammen!)  # Broadcast-Nachricht
user2.send_message(Hallo Xiaoming!, Xiaoming)  # Privater Chat

Implementierung des Mediator-Musters

Grundstruktur

Lassen Sie uns die Implementierung des Mediator-Musters anhand eines vollständigeren Beispiels verstehen:

Beispiel

from abc import ABC, abstractmethod
from typing import List

# Abstrakter Mediator
class Mediator(ABC):
    @abstractmethod
    def notify(self, sender: object, event: str, data: dict = None):
        pass

# Konkreter Mediator - Chatraum
class ChatRoomMediator(Mediator):
    def __init__(self):
        self.users: List[User] = []
   
    def add_user(self, user):
        self.users.append(user)
        user.set_mediator(self)
   
    def notify(self, sender, event, data=Keine):
        if event == "send_message":
            message = data.get("message")
            target_user = data.get("target_user")
           
            if target_user:  # Privater Chat
                for user in self.users:
                    if user.name == target_user:
                        user.receive_message(message, sender.name)
            else:  # Gruppenchat
                for user in self.users:
                    if user != sender:
                        user.receive_message(message, sender.name)
       
        elif event == "user_joined":
            message = fSystem: {sender.name} ist dem Chatraum beigetreten
            for user in self.users:
                if user != sender:
                    user.receive_message(message, System)

# Basis-Komponenten-Klasse
class BaseComponent:
    def __init__(self):
        self._mediator = None
   
    def set_mediator(self, mediator: Mediator):
        self._mediator = mediator

# Konkrete Komponente - Benutzer
class User(BaseComponent):
    def __init__(self, name):
        super().__init__()
        self.name = name
   
    def send_message(self, message, target_user=None):
        print(f{self.name} hat eine Nachricht gesendet: {message})
        self._mediator.notify(self, "send_message", {
            "message": message,
            "target_user": target_user
        })
   
    def join_chat(self):
        self._mediator.notify(self, "user_joined")
   
    def receive_message(self, message, from_name):
        print(f{self.name} hat eine Nachricht von {from_name} empfangen: {message})

# Verwendungsbeispiel
def main():
    # Den Mediator erstellen
    chat_room = ChatRoomMediator()
   
    # Benutzer erstellen
    alice = Benutzer("Alice")
    bob = Benutzer("Bob")
    charlie = Benutzer("Charlie")
   
    # Benutzer beim Chatraum registrieren
    chat_room.add_user(alice)
    chat_room.add_user(bob)
    chat_room.add_user(charlie)
   
    print(=== Chatraum-Demo ===)
   
    # Alice tritt dem Chatraum bei
    alice.join_chat()
   
    # Nachricht senden
    alice.send_message(Hallo zusammen, ich bin Alice!)
    bob.send_message(Willkommen Alice!)
    charlie.send_message(Hallo Alice!, "Alice")  # Privater Chat
   
    # Bob sendet eine Gruppennachricht
    bob.send_message(Ist jemand online?)

if __name__ == "__main__":
    main()

Ausgabe

=== 聊天室演示 ===
系统: Alice 加入了聊天室
Alice 发送消息: 大家好,我是 Alice!
Bob 收到来自 Alice 的消息: 大家好,我是 Alice!
Charlie 收到来自 Alice 的消息: 大家好,我是 Alice!
Bob 发送消息: 欢迎 Alice!
Alice 收到来自 Bob 的消息: 欢迎 Alice!
Charlie 收到来自 Bob 的消息: 欢迎 Alice!
Charlie 发送消息: Alice 你好!
Alice 收到来自 Charlie 的消息: Alice 你好!
Bob 发送消息: 有人在线吗?
Alice 收到来自 Bob 的消息: 有人在线吗?
Charlie 收到来自 Bob 的消息: 有人在线吗?

UML-Struktur des Mediator-Musters

Strukturbeschreibung

  • Mediator (Mediator-Schnittstelle): definiert die Kommunikationsschnittstelle
  • ConcreteMediator (konkreter Mediator): implementiert die Koordinationslogik und kennt alle Komponenten
  • BaseComponent (Basiskomponente): enthält eine Referenz auf den Mediator
  • ConcreteComponent (konkrete Komponente): implementiert konkrete Geschäftslogik

Anwendungsszenarien aus der Praxis

Szenario 1: GUI-Anwendung

In einer grafischen Benutzeroberfläche koordinieren verschiedene Steuerelemente (Schaltflächen, Textfelder, Kontrollkästchen usw.) Interaktionen über einen Mediator:

Beispiel

class DialogMediator:
    def __init__(self):
        self.login_button = None
        self.username_input = None
        self.password_input = None
        self.remember_checkbox = None
   
    def notify(self, sender, event):
        if event == "username_changed" or event == "password_changed":
            # Wenn Benutzername oder Passwort eingegeben wird, prüfen, ob die Anmeldeschaltfläche aktiviert werden kann
            username = self.username_input.get_text()
            password = self.password_input.get_text()
            self.login_button.set_enabled(bool(username and Passwort))
       
        elif event == "login_clicked":
            # Login-Logik behandeln
            username = self.username_input.get_text()
            password = self.password_input.get_text()
            remember = self.remember_checkbox.is_checked()
            print(fAnmeldung: {username}, Angemeldet bleiben: {remember})
       
        elif event == "remember_changed":
            print(Option 'Angemeldet bleiben' geändert)

class UIComponent:
    def __init__(self, mediator=None):
        self.mediator = mediator
   
    def set_mediator(self, mediator):
        self.mediator = mediator

class Button(UIComponent):
    def click(self):
        if self.mediator:
            self.mediator.notify(self, "login_clicked")
   
    def set_enabled(self, enabled):
        print(fButton {'Aktivieren' if enabled else 'Deaktivieren'})

class TextInput(UIComponent):
    def __init__(self, mediator=None):
        super().__init__(mediator)
        self._text = ""
   
    def set_text(self, text):
        self._text = text
        if self.mediator:
            self.mediator.notify(self, "username_changed")
   
    def get_text(self):
        return self._text

# Verwendungsbeispiel
dialog = DialogMediator()

login_btn = Button()
username_input = TextInput()
password_input = TextInput()

dialog.login_button = login_btn
dialog.username_input = username_input
dialog.password_input = password_input

login_btn.set_mediator(dialog)
username_input.set_mediator(dialog)
password_input.set_mediator(dialog)

# Benutzereingabe simulieren
username_input.set_text("user123")
password_input.set_text("pass123")
login_btn.click()

Szenario 2: E-Commerce-Bestellsystem

In einem E-Commerce-System umfasst die Auftragsabwicklung mehrere Teilsysteme wie Bestandsverwaltung, Zahlung und Logistik:

Beispiel

class OrderMediator:
    def __init__(self):
        self.inventory_system = None
        self.payment_system = None
        self.shipping_system = None
        self.notification_system = None
   
    def place_order(self, order_data):
        print(=== Bestellverarbeitung starten ===)
       
        # Lagerbestand prüfen
        if not self.inventory_system.check_stock(order_data):
            return Unzureichender Bestand
       
        # Zahlung verarbeiten
        payment_result = self.payment_system.process_payment(order_data)
        if not payment_result:
            return Zahlung fehlgeschlagen
       
        # Lagerbestand aktualisieren
        self.inventory_system.update_stock(order_data)
       
        # Versand veranlassen
        shipping_info = self.shipping_system.schedule_delivery(order_data)
       
        # Benachrichtigung senden
        self.notification_system.send_confirmation(order_data, shipping_info)
       
        return Bestellung erfolgreich verarbeitet

class InventorySystem:
    def check_stock(self, order_data):
        print(Lagerbestand wird geprüft...)
        return True
   
    def update_stock(self, order_data):
        print(Lagerbestand wird aktualisiert...)

class PaymentSystem:
    def process_payment(self, order_data):
        print(Zahlung wird verarbeitet...)
        return True

class ShippingSystem:
    def schedule_delivery(self, order_data):
        print(Versand wird arrangiert...)
        return Sendungsverfolgungsnummer: SF123456789

class NotificationSystem:
    def send_confirmation(self, order_data, shipping_info):
        print(fBestätigungs-E-Mail senden, Versandinformationen: {shipping_info})

# Verwendungsbeispiel
mediator = OrderMediator()

mediator.inventory_system = InventorySystem()
mediator.payment_system = PaymentSystem()
mediator.shipping_system = ShippingSystem()
mediator.notification_system = NotificationSystem()

order_data = {"product_id": "123", "quantity": 2, "user_id": "user001"}
result = mediator.place_order(order_data)
print(fBestellergebnis: {result})

Vor- und Nachteile des Mediator-Musters

Vorteile

Vorteile Beschreibung
Prinzip der einzigen Verantwortung Zentralisiert die Interaktionslogik zwischen Komponenten im Mediator.
Open/Closed-Prinzip Ermöglicht die Einführung neuer Mediatoren, ohne bestehende Komponenten zu ändern.
Reduziert Kopplung Reduziert direkte Abhängigkeiten zwischen Komponenten.
Einfache Wiederverwendung Einzelne Komponenten können in verschiedenen Kontexten leichter wiederverwendet werden.

Nachteile

Nachteile Beschreibung
Der Mediator kann komplex werden Mit zunehmender Interaktionslogik kann der Mediator zu einem Gott-Objekt werden.
Performance-Overhead Die gesamte Kommunikation läuft über den Mediator, was einen Leistungsengpass verursachen kann.
Schwierig zu debuggen Die Interaktionslogik ist im Mediator konzentriert, daher kann das Debugging die Verfolgung mehrerer Komponenten erfordern.

Best Practices und Überlegungen

1. Verantwortlichkeiten des Mediators sinnvoll aufteilen

Lassen Sie nicht zu, dass ein einziger Mediator alles übernimmt; Sie können mehrere Mediatoren nach Geschäftsdomänen aufteilen:

Beispiel

class UserRegistrationMediator:
    def notify(self, sender, event, data):
        if event == "user_registered":
            # Logik nach der Benutzerregistrierung behandeln
            self.send_welcome_email(data)
            self.create_user_profile(data)
            self.add_to_mailing_list(data)

class OrderProcessingMediator:
    def notify(self, sender, event, data):
        if event == "order_created":
            # Logik nach der Bestellerstellung behandeln
            self.validate_order(data)
            self.process_payment(data)
            self.update_inventory(data)

2. Vermeiden Sie einen übermäßig komplexen Mediator

Wenn der Mediator zu komplex wird, sollten Sie andere Muster oder Refactoring in Betracht ziehen:

Beispiel

# Schlechte Praxis - Mediator enthält zu viel Logik
class ComplexMediator:
    def handle_event(self, event_type, data):
        if event_type == "user_action":
            # Eine Menge komplexer Geschäftslogik...
            pass
        elif event_type == "system_event":
            # Komplexere Logik...
            pass

# Gute Praxis - Verwenden Sie das Strategiemuster, um komplexe Logik zu zerlegen
class EventHandler:
    def handle(self, data):
        pass

class UserActionHandler(EventHandler):
    def handle(self, data):
        # Benutzeraktionen gezielt behandeln
        pass

class SimpleMediator:
    def __init__(self):
        self.handlers = {}
   
    def register_handler(self, event_type, handler):
        self.handlers[event_type] = handler
   
    def notify(self, event_type, data):
        if event_type in self.handlers:
            self.handlers[event_type].handle(data)

3. Kombination mit dem Observer-Muster in Betracht ziehen

Das Mediator-Muster wird oft in Kombination mit dem Observer-Muster verwendet:

Beispiel

from abc import ABC, abstractmethod
from typing import List

class Observer(ABC):
    @abstractmethod
    def update(self, event, data):
        pass

class Observable:
    def __init__(self):
        self._observers: List[Observer] = []
   
    def add_observer(self, observer):
        self._observers.append(observer)
   
    def notify_observers(self, event, data=None):
        for observer in self._observers:
            observer.update(event, data)

class ChatMediator(Observable):
    def send_message(self, message, sender, receiver=Keine):
        # Mediator-Logik
        event_data = {
            "message": message,
            "sender": sender,
            "receiver": receiver
        }
        self.notify_observers("message_sent", event_data)

class LoggingObserver(Observer):
    def update(self, event, data):
        if event == "message_sent":
            print(fProtokoll: {data['sender']} hat eine Nachricht gesendet)

Übungsaufgaben

Übung 1: Verbessern Sie ein Chatraum-System

Erweitern Sie das vorherige Chatraum-System und fügen Sie die folgenden Funktionen hinzu:

  1. Unterstützen Sie die Erstellung mehrerer Chaträume
  2. Unterstützen Sie Benutzer beim Wechseln zwischen verschiedenen Chaträumen.
  3. Fügen Sie Administratorfunktionen hinzu (Benutzer kicken, stummschalten usw.)

Übung 2: Entwerfen Sie ein Flugticket-Buchungssystem

Verwenden Sie das Mediator-Muster, um ein Flugticket-Buchungssystem zu entwerfen, das die folgenden Komponenten enthält:

  • Flugabfrage
  • Sitzplatzauswahl
  • Zahlungsabwicklung
  • Ticketgenerierung
  • Benachrichtigungsversand

Die Komponenten müssen über den Mediator koordiniert zusammenarbeiten.

Übung 3: Smart-Home-Steuerungssystem

Entwerfen Sie ein Smart-Home-Steuerungssystem, das Folgendes umfasst:

  • Beleuchtungssteuerung
  • Temperaturregelung
  • Sicherheitsüberwachung
  • Szenenmodus

Implementieren Sie eine intelligente geräteübergreifende Verknüpfung über den Mediator.


Zusammenfassung

Das Mediator-Muster ist ein leistungsstarkes Werkzeug für den Umgang mit komplexen Objektinteraktionen. Es vereinfacht die Systemarchitektur durch die Einführung eines Koordinationszentrums und eignet sich besonders für die folgenden Szenarien:

  • Zwischen Objekten bestehen komplexe vernetzte Interaktionsbeziehungen
  • Wenn die Interaktionslogik zwischen mehreren Objekten zentral gesteuert werden muss
  • Kopplung zwischen Objekten reduzieren möchten

Denken Sie daran: Das Mediator-Muster ist kein Allheilmittel. Wenn die Interaktionslogik einfach ist, kann die direkte Kommunikation von Objekt zu Objekt geeigneter sein. Bei komplexen Systemen kann jedoch der richtige Einsatz des Mediator-Musters die Wartbarkeit und Erweiterbarkeit des Codes erheblich verbessern.

Wichtige Punkte:

  • Der Mediator kapselt die Interaktionslogik zwischen Objekten
  • Komponenten kommunizieren nur mit dem Mediator und sind nicht direkt voneinander abhängig
  • Der Mediator kann komplex werden und erfordert ein sorgfältiges Design
  • Die Kombination mit anderen Mustern (wie Observer) kann bessere Ergebnisse erzielen
Weitere Erweiterungen