Stellen Sie sich vor, Sie müssen den Code einer anderen Person verwenden, der wie folgt aufgebaut ist:
class Messy {
String concat(String param, String str) { /* ... */ }
boolean contains(String param, String s) { /* ... */ }
boolean isEmpty(String param) { /* ... */ }
boolean matches(String param, String regex) { /* ... */ }
boolean startsWith(String param, String prefix) { /* ... */ }
}
Stellen Sie sich nun vor, Sie stellen fest, dass Ihr Code, der davon abhängt, wie folgt aussieht:
String process(String param) {
Messy messy = new Messy();
if (messy.contains(param, "whatever")) {
return messy.concat(param, "-contains");
}
if (messy.isEmpty(param)) {
return messy.concat(param, "-empty");
}
if (messy.matches(param, "[whatever]")) {
return messy.concat(param, "-matches");
}
if (messy.startsWith(param, "whatever")) {
return messy.concat(param, "-startsWith");
}
return messy.concat(param, "-whatever");
// WTF do I really need to repeat bloody "param" 9 times above?
}
... und dass Sie die Verwendung vereinfachen möchten, um insbesondere die wiederholte Verwendung von Parametern zu vermeiden, die für Ihre Anwendung nicht benötigt werden.
Okay, Sie beginnen mit dem Aufbau einer Antikorruptionsschicht.
Stellen Sie als Erstes sicher, dass Ihr "Hauptcode" nicht Messy
direkt darauf verweist . Beispielsweise ordnen Sie das Abhängigkeitsmanagement so an, dass der Zugriff Messy
nicht kompiliert werden kann.
Zweitens erstellen Sie ein dediziertes "Ebenen" -Modul, auf das nur zugegriffen wird, Messy
und setzen es Ihrem "Hauptcode" auf eine Weise aus, die für Sie sinnvoller ist.
Der Ebenencode würde folgendermaßen aussehen:
class Reasonable { // anti-corruption layer
String param;
Messy messy = new Messy();
Reasonable(String param) {
this.param = param;
}
String concat(String str) { return messy.concat(param, str); }
boolean contains(String s) { return messy.contains(param, s); }
boolean isEmpty() { return messy.isEmpty(param); }
boolean matches(String regex) { return messy.matches(param, regex); }
boolean startsWith(String prefix) { return messy.startsWith(param, prefix); }
}
Als Ergebnis sieht Ihr „Hauptcode“ nicht mit Zohan an Messy
, indem Reasonable
stattdessen etwa wie folgt:
String process(String param) {
Reasonable reasonable = new Reasonable(param);
// single use of "param" above and voila, you're free
if (reasonable.contains("whatever")) {
return reasonable.concat("-contains");
}
if (reasonable.isEmpty()) {
return reasonable.concat("-empty");
}
if (reasonable.matches("[whatever]")) {
return reasonable.concat("-matches");
}
if (reasonable.startsWith("whatever")) {
return reasonable.concat("-startsWith");
}
return reasonable.concat("-whatever");
}
Beachten Sie, dass es immer noch ein bisschen Chaos gibt, Messy
aber dies ist jetzt ziemlich tief im Inneren verborgen Reasonable
, was Ihren "Hauptcode" einigermaßen sauber und frei von Korruption macht, die durch die direkte Verwendung von Messy
Dingen dorthin gebracht würde .
Das obige Beispiel basiert auf der Erklärung der Antikorruptionsschicht im c2-Wiki:
Wenn Ihre Anwendung mit einer Datenbank oder einer anderen Anwendung arbeiten muss, deren Modell für das von Ihnen gewünschte Modell in Ihrer eigenen Anwendung unerwünscht oder nicht anwendbar ist, verwenden Sie eine Antikorruptions-Schicht, um in dieses und deins Modell zu übersetzen.
Hinweis Das Beispiel wurde absichtlich vereinfacht und komprimiert, um die Erklärung kurz zu halten.
Wenn Sie hinter der Anti-Korruptions-Ebene ein größeres Durcheinander an APIs haben, gilt der gleiche Ansatz: Stellen Sie zunächst sicher, dass Ihr "Hauptcode" nicht direkt auf beschädigte Inhalte zugreift, und legen Sie ihn dann auf eine umfassendere Weise offen bequem in Ihrem Nutzungskontext.
Berücksichtigen Sie beim "Skalieren" Ihrer Ebene über ein vereinfachtes Beispiel hinaus, dass es nicht unbedingt eine triviale Aufgabe ist, die API komfortabel zu gestalten. Investieren Sie eine Anstrengung , um Ihre Schicht die richtige Art und Weise zu entwerfen , überprüft die beabsichtigte Verwendung mit Unit - Tests usw.
Mit anderen Worten, stellen Sie sicher, dass Ihre API tatsächlich eine Verbesserung gegenüber der verborgenen API darstellt , und stellen Sie sicher, dass Sie nicht nur eine weitere Ebene der Korruption einführen.
Beachten Sie der Vollständigkeit halber subtile, aber wichtige Unterschiede zwischen diesem und verwandten Mustern Adapter und Fassade . Wie durch den Namen angegeben, geht die Antikorruptionsschicht davon aus, dass die zugrunde liegende API Qualitätsprobleme aufweist ("beschädigt" ist) und beabsichtigt, einen Schutz für die genannten Probleme anzubieten.
Sie können es auf diese Art und Weise denken: Wenn Sie diese Bibliothek Designer wäre besser rechtfertigen kann seine Funktionalität mit off Belichtung Reasonable
statt Messy
, würde dies bedeuten , Sie auf Anti - Korruptions - Ebene arbeiten, tun ihre Arbeit, Festsetzung ihre Design - Fehler.
Im Gegensatz dazu treffen Adapter und Facade keine Annahmen über die Qualität des zugrunde liegenden Designs. Diese können auf APIs angewendet werden, die für den Anfang gut konzipiert sind und nur an Ihre spezifischen Anforderungen angepasst werden.
Tatsächlich könnte es sogar produktiver sein anzunehmen, dass Muster wie Adapter und Facade voraussetzen, dass der zugrunde liegende Code gut gestaltet ist. Sie können sich das so vorstellen: Gut gestalteter Code sollte für bestimmte Anwendungsfälle nicht zu schwierig zu optimieren sein. Wenn sich herausstellt, dass das Design Ihres Adapters aufwändiger ist als erwartet, kann dies darauf hinweisen, dass der zugrunde liegende Code irgendwie "beschädigt" ist. In diesem Fall können Sie den Auftrag in verschiedene Phasen aufteilen: Richten Sie zunächst eine Antikorruptionsschicht ein, um die zugrunde liegende API ordnungsgemäß zu strukturieren, und entwerfen Sie anschließend Ihren Adapter / Ihre Fassade über dieser Schutzschicht.
In other words, make sure that your API is indeed an improvement over one it hides, make sure that you don't just introduce another layer of corruption.
Dieser gesamte Abschnitt verdient ein fett gedrucktes Etikett.Um eine andere Quelle zu zitieren:
Eric Evans, Domain Driven Design, 16. Druck, Seite 365
Das Wichtigste ist, dass auf jeder Seite der Antikorruptionsschicht unterschiedliche Begriffe verwendet werden. Ich habe einmal an einem System für die Transportlogistik gearbeitet. Runden mussten geplant werden. Sie mussten das Fahrzeug in einem Depot ausrüsten, zu verschiedenen Kundenstandorten fahren, diese warten und andere Orte wie Tankstopps besuchen. Auf der höheren Ebene ging es jedoch nur um Aufgabenplanung. Daher war es sinnvoll, die allgemeineren Begriffe der Aufgabenplanung von den sehr spezifischen Begriffen der Transportlogistik zu trennen.
Bei einer Anti-Korruptions-Layer-Isolierung geht es also nicht nur darum, Sie vor unordentlichem Code zu schützen, sondern auch darum, verschiedene Domänen voneinander zu trennen und sicherzustellen, dass sie auch in Zukunft voneinander getrennt bleiben.
quelle
Adapter
Wenn Sie inkompatible Schnittstellen haben, die eine ähnliche Logik ausführen, um eine in die andere anzupassen, so dass Sie Implementierungen der einen mit Dingen verwenden können, die die andere erwarten.
Beispiel:
Sie haben ein Objekt, das ein Auto haben soll, aber Sie haben nur eine 4WheelVehicle-Klasse, also erstellen Sie ein CarBuiltUsing4WheelVehicle und verwenden dieses als Ihr Auto.
Fassade
Wenn Sie eine komplexe / verwirrende / gigantische API haben und diese einfacher / übersichtlicher / kleiner gestalten möchten. Sie erstellen eine Fassade, um die Komplexität / Verwirrung / Extras zu verbergen und nur eine neue einfache / klare / kleine API verfügbar zu machen.
Beispiel:
Sie verwenden eine Bibliothek mit 100 Methoden. Um eine bestimmte Aufgabe auszuführen, müssen Sie eine Reihe von Initialisierungs-, Verbindungs-, Öffnungs- und Schließvorgängen ausführen, um endlich in der Lage zu sein, das zu tun, was Sie wollten, und alles, was Sie wollten, ist eine Funktion von Sie können also eine Fassade erstellen, die nur eine Methode für die 1 Funktion enthält, die Sie benötigen, und die die gesamte Initialisierung, Reinigung usw. für Sie erledigt.
Anti-Korruptions-Schicht
Wenn Sie ein System haben, das sich nicht in Ihrer Domäne befindet, Ihre geschäftlichen Anforderungen es jedoch erfordern, dass Sie mit dieser anderen Domäne arbeiten. Sie möchten diese andere Domain nicht in Ihre eigene Domain einbinden, wodurch sie beschädigt wird. Daher übersetzen Sie das Konzept Ihrer Domain in diese andere Domain und umgekehrt.
Beispiel:
Ein System zeigt den Kunden mit einem Namen und einer Liste von Zeichenfolgen an, eine für jede Transaktion. Sie betrachten Profile als eigenständige Klassen mit einem Namen und Transaktionen als eigenständige Klassen mit einer Zeichenfolge und Kunden als ein Profil und eine Sammlung von Transaktionen.
Sie erstellen also eine ACL-Ebene, mit der Sie die Übersetzung zwischen Ihrem Kunden und dem Kunden des anderen Systems durchführen können. Auf diese Weise müssen Sie nie den Kunden des anderen Systems verwenden, sondern lediglich die ACL informieren: "Geben Sie mir den Kunden mit Profil X, und die ACL weist das andere System an, ihm einen Kunden mit dem Namen X.name zuzuweisen, und kehrt zurück Sie ein Kunde mit Profil X.
===================
Alle drei sind relativ ähnlich, weil sie alle Indirektionsmuster sind. Sie befassen sich jedoch mit unterschiedlichen Strukturen, Klassen / Objekten im Vergleich zu APIs im Vergleich zu Modulen / Subsystemen. Sie könnten sie alle kombinieren, wenn Sie müssten. Das Subsystem verfügt über eine komplexe API, sodass Sie eine FASSADE dafür erstellen. Es wird ein anderes Modell verwendet. Daher würden Sie diese Daten für jede Datendarstellung, die nicht zu Ihrem Modell passt, wieder in die Art und Weise übersetzen, in der Sie sie modellieren. Schließlich sind die Schnittstellen möglicherweise auch nicht kompatibel, sodass Sie ADAPTER zum Anpassen von einem zum anderen verwenden würden.
quelle
Viele Antworten hier besagen, dass es in ACLs "nicht nur" darum geht, unordentlichen Code zu verpacken. Ich würde noch weiter gehen und sagen, dass das überhaupt nicht der Fall ist, und wenn, dann ist das ein Nebeneffekt.
In einer Anti-Korruptions-Ebene geht es darum, eine Domäne einer anderen zuzuordnen, damit Dienste, die die zweite Domäne verwenden, nicht durch Konzepte aus der ersten "beschädigt" werden müssen. ACLs beziehen sich auf Domänenmodelle und Adapter auf Klassen. Sie finden nur auf einer anderen Ebene statt. Der Adapter ist wohl das wichtigste Entwurfsmuster - ich verwende es die ganze Zeit -, aber die Beurteilung der verpackten Klasse als chaotisch oder nicht, ist irrelevant. Es ist was es ist, ich brauche nur eine andere Schnittstelle.
Das Fokussieren auf Unordnung ist irreführend und verpasst den Sinn dessen, worum es bei DDD geht. Bei ACLs geht es darum, konzeptionelle Inkongruenzen zu beheben, nicht um schlechte Qualität.
quelle