Ersetzen direkter Abhängigkeiten durch Messaging

Manchmal muss ein Modul nur andere darüber informieren, dass einige Ereignisse/Änderungen in ihm aufgetreten sind, und es spielt keine Rolle, was später mit diesen Informationen passiert.

In diesem Fall müssen die Module überhaupt nicht „voneinander wissen“, also direkte Links enthalten und direkt interagieren, sondern es reicht aus, nur Nachrichten (Nachrichten) oder Ereignisse (Ereignisse) auszutauschen.

Manchmal scheint es, dass die Modulkommunikation über Messaging viel schwächer ist als die direkte Abhängigkeit. Da die Methoden nicht aufgerufen werden, gibt es tatsächlich keine Informationen über die Klassen. Aber das ist nichts weiter als eine Illusion.

Anstelle von Methodennamen wird die Logik an Nachrichtentypen, deren Parameter und übertragene Daten gebunden. Die Konnektivität solcher Module ist verschmiert.

Früher war es so: Wir rufen Methoden auf – es gibt Konnektivität, wir rufen keine Methoden auf – es gibt keine Konnektivität. Stellen Sie sich nun vor, dass Modul A beginnt, in seinen Nachrichten leicht unterschiedliche Daten zu senden. Gleichzeitig funktionieren alle von diesen Nachrichten abhängigen Module nicht ordnungsgemäß.

Angenommen, früher, beim Hinzufügen eines neuen Benutzers, hat das Autorisierungsmodul die Nachricht USER_ADDED gesendet und nach der Aktualisierung begonnen, diese Nachricht beim Versuch, sich zu registrieren, zu senden und zusätzlich in den Parametern anzugeben, ob die Registrierung erfolgreich war oder nicht.

Daher ist es sehr wichtig, den Nachrichtenmechanismus sehr kompetent zu implementieren. Hierfür gibt es verschiedene Vorlagen.

Beobachter. Es wird im Fall einer Eins-zu-Viele-Abhängigkeit verwendet, wenn viele Module vom Status eines Moduls, des Hauptmoduls, abhängen. Es verwendet den Mailing-Mechanismus, was bedeutet, dass das Hauptmodul einfach die gleichen Nachrichten an alle seine Abonnenten sendet und die an diesen Informationen interessierten Module die „Abonnenten“-Schnittstelle implementieren und sich in die Mailingliste eintragen.

Dieser Ansatz wird häufig in Systemen mit einer Benutzeroberfläche verwendet, die es dem Kern der Anwendung (Modell) ermöglicht, unabhängig zu bleiben und gleichzeitig die zugehörigen Schnittstellen darüber zu informieren, dass sich etwas geändert hat und aktualisiert werden muss.

Dabei ist das Nachrichtenformat auf Betriebssystemebene standardisiert, deren Entwickler auf Abwärtskompatibilität und gute Dokumentation achten müssen.

Die Organisation der Interaktion durch die Verteilung von Nachrichten hat einen zusätzlichen „Bonus“ – die optionale Existenz von „Abonnenten“ für „veröffentlichte“ (d. h. versendete) Nachrichten. Ein gut durchdachtes System wie dieses ermöglicht das jederzeitige Hinzufügen/Entfernen von Modulen.

Nachrichtenbus

Sie können den Austausch von Nachrichten organisieren und dafür das Mediator- Muster auf andere Weise nutzen .

Es wird verwendet, wenn zwischen Modulen eine Viele-zu-Viele-Abhängigkeit besteht. Der Mediator fungiert als Vermittler bei der Kommunikation zwischen Modulen, fungiert als Kommunikationszentrum und macht es überflüssig, dass Module explizit aufeinander verweisen.

Dadurch wird die Interaktion der Module untereinander („alle mit allen“) durch die Interaktion der Module nur mit einem Vermittler („eins mit allen“) ersetzt. Der Mediator soll die Interaktion zwischen mehreren Modulen kapseln.

Nachrichtenbus

Dabei handelt es sich um den sogenannten Smart Intermediary . Dort beginnen Entwickler am häufigsten damit, ihre Krücken anzubringen, die das Verhalten einzelner Module beeinflussen, indem sie den Empfang bestimmter Nachrichten ein- und ausschalten.

Ein typisches Beispiel aus der Praxis ist die Verkehrskontrolle am Flughafen. Alle Nachrichten von Flugzeugen gehen an den Kontrollturm des Fluglotsen, anstatt direkt zwischen Flugzeugen gesendet zu werden. Und der Fluglotse trifft bereits Entscheidungen darüber, welche Flugzeuge starten oder landen dürfen, und sendet im Gegenzug Nachrichten an die Flugzeuge.

Wichtig! Module können sich gegenseitig nicht nur einfache Nachrichten, sondern auch Befehlsobjekte senden. Eine solche Interaktion wird durch die Befehlsvorlage beschrieben. Die Quintessenz besteht darin, eine Anforderung zum Ausführen einer bestimmten Aktion als separates Objekt zu kapseln.

Tatsächlich enthält dieses Objekt eine einzige Methode „execute()“ , mit der Sie diese Aktion dann als Parameter an andere Module zur Ausführung übergeben und im Allgemeinen alle Operationen mit dem Befehlsobjekt ausführen können, die für normale Objekte ausgeführt werden können.

Gesetz von Demeter

Das Gesetz von Demeter verbietet die Verwendung impliziter Abhängigkeiten: „Objekt A darf nicht direkt auf Objekt C zugreifen können, wenn Objekt A Zugriff auf Objekt B und Objekt B Zugriff auf Objekt C hat.“

Das bedeutet, dass alle Abhängigkeiten im Code „explizit“ sein müssen – Klassen/Module können bei ihrer Arbeit nur „ihre Abhängigkeiten“ verwenden und sollten diese nicht auf andere übertragen. Ein gutes Beispiel ist eine dreistufige Architektur. Die Schnittstellenschicht sollte mit der Logikschicht zusammenarbeiten, aber nicht direkt mit der Datenbankschicht interagieren.

Kurz gesagt wird dieser Grundsatz auch so formuliert: „Interagieren Sie nur mit unmittelbaren Freunden und nicht mit Freunden von Freunden.“ Dadurch wird eine geringere Kohärenz des Codes sowie eine größere Sichtbarkeit und Transparenz seines Designs erreicht.

Das Demeter-Gesetz setzt das bereits erwähnte „Prinzip des minimalen Wissens“ um, das der losen Kopplung zugrunde liegt und darin besteht, dass ein Objekt/Modul möglichst wenige Details über die Struktur und Eigenschaften anderer Objekte/Module kennen sollte und alles im Allgemeinen, einschließlich seiner eigenen Komponenten .

Eine Analogie aus dem Leben: Wenn Sie möchten, dass der Hund rennt, ist es dumm, seinen Pfoten Befehle zu geben. Es ist besser, dem Hund den Befehl zu geben, und er wird sich selbst um seine Pfoten kümmern.

Komposition statt Vererbung

Dies ist ein sehr umfangreiches und interessantes Thema, das zumindest einen eigenen Vortrag verdient. Zu diesem Thema wurden im Internet viele Kopien veröffentlicht, bis ein Konsens erzielt wurde – wir nutzen die Vererbung auf ein Minimum, die Zusammensetzung auf das Maximum.

Der Punkt ist, dass Vererbung tatsächlich die stärkste Verbindung zwischen Klassen herstellt und daher vermieden werden sollte. Dieses Thema wird in Herb Sutters Artikel „ Prefer Composition Over Inheritance “ ausführlich behandelt.

Wenn Sie anfangen, Designmuster zu erlernen, werden Sie auf eine ganze Reihe von Mustern stoßen, die die Erstellung eines Objekts oder seine interne Struktur steuern. Übrigens kann ich in diesem Zusammenhang dazu raten, auf das Delegate/Delegate- Muster und das Component- Muster zu achten, die aus Spielen stammen .

Wir werden etwas später mehr über Muster sprechen.