Was ist eine Antikorruptionsschicht und wie wird sie verwendet?


151

Ich versuche herauszufinden, was die Antikorruptionsschicht wirklich bedeutet. Ich weiß, dass es eine Möglichkeit ist, alten Code oder schlechte APIs zu umgehen. Was ich nicht verstehe ist, wie es funktioniert und was es zu einer sauberen Trennung von der unerwünschten Schicht macht.

Ich habe nach etwas gesucht, aber ich kann keine einfachen Beispiele oder Erklärungen finden, deshalb suche ich jemanden, der das versteht und es mit einfachen Beispielen erklären kann. Eine Antwort, die meine Frage beantworten würde, sollte einfach (nicht unbedingt kurz) sein und verständliche Beispiele für die Implementierung und Verwendung liefern.

Siehe diese Frage für meinen Anwendungsfall.

Antworten:


147

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.

  1. Stellen Sie als Erstes sicher, dass Ihr "Hauptcode" nicht Messydirekt darauf verweist . Beispielsweise ordnen Sie das Abhängigkeitsmanagement so an, dass der Zugriff Messynicht kompiliert werden kann.

  2. Zweitens erstellen Sie ein dediziertes "Ebenen" -Modul, auf das nur zugegriffen wird, Messyund 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 Reasonablestattdessen 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, Messyaber 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 MessyDingen 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 Reasonablestatt 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.


1
Wie skaliert das, wenn es eine ganze Struktur abhängiger API-Klassen gibt? Ist es noch besser zu handhaben als die Ebene, vor der es den Rest der Anwendung schützt?
Knownasilya

1
@ Knownasilya, das ist eine sehr gute Frage, Antwort erweitert, um das zu adressieren
Mücke

4
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.
Lilienthal,

19
Anti-Korruptions-Schichten haben nichts mit dem Umgang mit APIs von schlechter Qualität zu tun. Es geht darum, konzeptionelle Inkongruenzen zu beseitigen und Domänen anzupassen, die wir nur verwenden könnten, indem wir unseren Code in Domänen "verfälschen", die wir leichter verwenden können.
Ian Fairman

8
Ian Fairman hat es richtig verstanden, während der Autor dieser Antwort dies definitiv nicht tat. Wenn Sie zur Quelle des Konzepts (dem DDD-Buch) gehen, werden Sie mindestens zwei Dinge finden, die dieser Antwort widersprechen: 1) Es wird eine Antikorruptionsschicht erstellt, um zu vermeiden, dass das neue Domänenmodell, das wir mit Elementen entwickeln, beschädigt wird aus dem Modell eines bestehenden externen Systems; es ist nicht so, dass das andere System "korrupt" ist, in der Tat kann es perfekt gut und gut gestaltet sein; 2) eine Anti-Korruptions - Schicht wird in der Regel mehrere Klassen enthalten, oft einschließlich Fassaden und Adapter sowie Dienstleistungen .
Rogério

41

Um eine andere Quelle zu zitieren:

Erstellen Sie eine isolierende Ebene, um Clients Funktionen für ihr eigenes Domänenmodell bereitzustellen. Die Schicht kommuniziert über ihre vorhandene Schnittstelle mit dem anderen System und erfordert nur geringe oder keine Änderungen am anderen System. Intern wird die Ebene zwischen den beiden Modellen nach Bedarf in beide Richtungen verschoben.

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.


6
Dies ist sehr wichtig! Eine ACL soll nicht nur mit Messy-Code verwendet werden, sondern auch zur Kommunikation zwischen begrenzten Kontexten. Es wird von einem Kontext in den anderen übersetzt, sodass die Daten in jedem Kontext die Sprache und die Art und Weise widerspiegeln, in der dieser Kontext über die Daten denkt und darüber spricht.
Didier A.

29

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.


12

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.