Warum nicht einen IoC-Container verwenden, um Abhängigkeiten für Entitäten / Geschäftsobjekte aufzulösen?

82

Ich verstehe das Konzept hinter DI, aber ich lerne gerade, was verschiedene IoC-Container können. Es scheint, dass die meisten Leute die Verwendung von IoC-Containern befürworten, um zustandslose Dienste zu verkabeln, aber was ist mit der Verwendung für zustandsbehaftete Objekte wie Entitäten?

Ob es richtig oder falsch ist, ich stopfe meine Entitäten normalerweise mit Verhalten, selbst wenn dieses Verhalten eine externe Klasse erfordert. Beispiel:

public class Order : IOrder
{

    private string _ShipAddress;
    private IShipQuoter _ShipQuoter;

    public Order(IOrderData OrderData, IShipQuoter ShipQuoter)
    {
        // OrderData comes from a repository and has the data needed 
        // to construct order
        _ShipAddress = OrderData.ShipAddress;  // etc.
        _ShipQuoter = ShipQuoter;

    }

    private decimal GetShippingRate()
    {
        return _ShipQuoter.GetRate(this);
    }
}

Wie Sie sehen können, sind die Abhängigkeiten Konstruktor injiziert. Nun zu ein paar Fragen.

  1. Wird es als schlechte Praxis angesehen, wenn Ihre Entitäten von externen Klassen wie dem ShipQuoter abhängig sind? Das Eliminieren dieser Abhängigkeiten scheint mich zu einer anämischen Domäne zu führen, wenn ich die Definition richtig verstehe.

  2. Ist es eine schlechte Praxis, einen IoC-Container zu verwenden, um diese Abhängigkeiten aufzulösen und bei Bedarf eine Entität zu erstellen? Ist das möglich?

Vielen Dank für jeden Einblick.

Casey Wilkins
quelle
3
Mach einfach Dinge, die du brauchst, weil es deine Arbeit einfacher macht, nicht weil du es wahrscheinlich so machen solltest
Omu
28
Als autodidaktischer Programmierer bin ich diesen Weg gegangen und er führte zu der Software, die derzeit von meinem Unternehmen verwendet wird. Eine prozedurale / Transaktionsskript-basierte Software entstand, teilweise weil sie am einfachsten war und Party, weil ich es nicht besser wusste. Es ist absolut schmerzhaft zu pflegen und zu erweitern, weshalb ich mir die Zeit nehme, es neu zu schreiben und Rat von Leuten einzuholen, die diese Probleme bereits überwunden haben, wie man nicht dieselben Fehler macht.
Casey Wilkins
1
verwandt: stackoverflow.com/questions/827670/…
Ruben Bartelink

Antworten:

90

Die erste Frage ist am schwierigsten zu beantworten. Ist es eine schlechte Praxis, wenn Entitäten von externen Klassen abhängig sind? Es ist sicherlich nicht die häufigste Sache.

Wenn Sie beispielsweise ein Repository in Ihre Entitäten einfügen, haben Sie effektiv eine Implementierung des Active Record-Musters . Einige Leute mögen dieses Muster aus Bequemlichkeitsgründen, während andere (wie ich) es als Codegeruch oder Anti-Muster betrachten, weil es gegen das Prinzip der Einzelverantwortung verstößt (SRP) .

Sie könnten argumentieren, dass das Einfügen anderer Abhängigkeiten in Entitäten Sie in die gleiche Richtung ziehen würde (weg von SRP). Auf der anderen Seite haben Sie sicherlich Recht, dass, wenn Sie dies nicht tun, die Anziehungskraft auf ein anämisches Domänenmodell gerichtet ist .

Ich hatte lange Zeit mit all dem zu kämpfen, bis ich auf Greg Youngs (aufgegebenes) Papier über DDDD stieß, in dem er erklärt, warum die stereotype n-Tier / n-Layer-Architektur immer CRUDy (und damit eher anämisch) sein wird.

Wenn wir uns darauf konzentrieren, Domänenobjekte als Befehle und Ereignisse anstelle von Substantiven zu modellieren , können wir möglicherweise ein geeignetes objektorientiertes Domänenmodell erstellen.

Die zweite Frage ist leichter zu beantworten. Sie können jederzeit eine Abstract Factory verwenden, um Instanzen zur Laufzeit zu erstellen . Mit Castle Windsor können Sie sogar die Typed Factory Facility nutzen, um die Fabriken nicht manuell zu implementieren.

Mark Seemann
quelle
Danke Mark. Ich habe die Typed Factory gesehen und Ihre anderen Beiträge zur Abstract Factory-Methode gelesen, aber ich habe noch nie Beispiele dafür gesehen, wie sie zum Auflösen von Entitäten verwendet werden. Liegt das daran, dass die meisten Benutzer ihre Entitäten ohne Abhängigkeiten außer einem Repository entwerfen? Bekomme ich später Probleme, wenn ich etwas wie Typed Factory rigoros verwende, um meine Entitäten mit externen Abhängigkeiten aufzulösen?
Casey Wilkins
Ich habe versucht zu sagen, dass, wenn Ihre Entitäten andere Mitarbeiter enthalten, die möglicherweise auf andere Entitäten usw. zugreifen, möglicherweise alle Arten von Wartungsproblemen auftreten - ganz zu schweigen von den SRP-Verstößen und den N + 1-Problemen. Aus diesem Grund empfiehlt Evans, jede Entität als aggregierte Wurzel zu behandeln.
Mark Seemann
In meinem Beispiel ruft ShipQuoter die Versandkosten für eine Bestellung von einem Webservice (z. B. UPS) ab. Würden Sie dies zu einem Service machen, der IOrder akzeptiert, oder würden Sie es zu einem Teil des Domain-Objekts wie Order.GetRates machen?
Casey Wilkins
Ich würde viel Zeit damit verbringen, herauszufinden, wie ich ein synchrones Ziehen überhaupt vermeiden könnte. Je mehr Sie Daten synchron und blockierend abrufen, desto spröder wird Ihr Design. Deshalb ist CQRS eine so attraktive Alternative.
Mark Seemann
4
Ihr Link zu Gregs Papier ist tot. Aber es ist immer noch hier verfügbar . Und es scheint, dass dies eine neuere Version ist.
BornToCode
1

Ich weiß, dass dies ein alter Beitrag ist, wollte ihn aber hinzufügen. Die Domänenentität sollte auch dann nicht bestehen bleiben, wenn Sie ein abstrahiertes Repository in ctor übergeben. Der Grund, warum ich dies vorschlage, ist nicht nur, dass es gegen SRP verstößt, sondern auch gegen die Aggregation von DDD. Lassen Sie mich erklären, dass DDD für komplexe Apps mit inhärent tiefen Diagrammen geeignet ist. Daher verwenden wir aggregierte oder zusammengesetzte Wurzeln, um Änderungen an den zugrunde liegenden "Kindern" beizubehalten. Wenn wir also den einzelnen Kindern Persistenz verleihen, verletzen wir die Beziehung, die Kinder zu den Kindern haben zusammengesetzte oder aggregierte Wurzel, die für den Lebenszyklus oder die Aggregation "verantwortlich" sein sollte. Natürlich bleibt die zusammengesetzte Wurzel oder das zusammengesetzte Aggregat auch nicht in ihrem eigenen Diagramm erhalten. Ein weiteres Problem beim Injizieren von Abhängigkeiten von DDD-Objekten besteht darin, dass ein injiziertes Domänenobjekt effektiv keinen Status hat, bis ein anderes Ereignis stattfindet, um seinen Status zu hydratisieren. Jeder Benutzer des Codes muss zuerst das Domänenobjekt initiieren oder einrichten, bevor er ein Geschäftsverhalten aufrufen kann, das die Kapselung verletzt.

user1538467
quelle