Frage

Ich habe einige der Fragen zu anämischen Domänenmodellen und Trennung von Bedenken lesen. Was sind die besten Techniken zur Durchführung / Domain-Logik auf anämischen Domänenobjekte angebracht? Bei meiner Arbeit haben wir ein ziemlich blutarm Modell, und wir sind zur Zeit als „Helfer“ Klassen der Datenbank / Business-Logik auf den Domänenobjekte auszuführen. Zum Beispiel:

public class Customer
{
    public string Name {get;set;}
    public string Address {get;set;}
}

public class Product
{
    public string Name {get;set;}
    public decimal Price {get;set;}
}

public class StoreHelper
{
    public void PurchaseProduct(Customer c, Product p)
    {
         // Lookup Customer and Product in db
         // Create records for purchase
         // etc.
    }
}

Wenn die App einen Kauf tun muss, würde es die StoreHelper erstellen und die Methode auf die Domain-Objekte aufrufen. Für mich wäre es sinnvoll, für den Kunden / Produkt machen zu wissen, wie sich in einem Repository zu speichern, aber Sie würden wahrscheinlich nicht wollen Save () Methoden auf den Domänenobjekten. Es wäre auch sinnvoll, für ein Verfahren wie Customer.Purchase (Produkt) machen, aber das ist auf der Entität Domain Logik setzen.

Hier sind einige Techniken, die ich kenne, nicht sicher, was gut / schlecht sind:

  1. Kunden- und Produkt erben von einer „Entity“ Klasse, die die grundlegenden CRUD-Operationen in einer generischen Art und Weise bietet (unter Verwendung eines ORM vielleicht).
    • Pros: Jedes Datenobjekt würde die CRUD-Operationen automatisch erhalten, aber werden dann in die Datenbank / ORM
    • gebunden
    • Nachteile: Dies löst nicht das Problem der Geschäftstätigkeit auf den Objekten, und bindet auch alle Domänenobjekte zu einer Basis Entity, die nicht geeignet sein könnte
  2. Verwenden Hilfsklassen, die CRUD-Operationen und Geschäftslogik zu handhaben
    • Ist es sinnvoll DAOs für die „reine Datenbank“ -Operationen zu haben, und separate Geschäfts Helfer für die weitere geschäftsspezifische Operationen?
    • Ist es besser, zu verwenden, nicht-statische oder statische Hilfsklassen für das?
    • Pros: Domain-Objekte sind nicht auf eine Datenbank / Business-Logik gebunden (völlig anämisch)
    • Nachteile: nicht sehr OO, nicht sehr natürliche Helfer im Anwendungscode zu verwenden (sieht aus wie C-Code)
  3. Verwenden Sie die Double-Dispatch-Technik, wo das Unternehmen Methoden hat zu einem beliebigen Repository zu speichern
    • Vorteile: bessere Trennung von Bedenken
    • Nachteile: Einheiten haben einige zusätzliche Logik angebracht (obwohl es entkoppelt)
  4. In C # 3.0, könnten Sie Erweiterungsmethoden verwenden, um die CRUD / Geschäftsmethoden zu einem Domain-Objekt zu befestigen, ohne es zu berühren
    • Ist das ein brauchbares Konzept? Was sind Vor / Nachteile?
  5. Andere Techniken?

Was sind die besten Techniken, um dies für den Umgang mit? Ich bin ziemlich neu in DDD (Ich bin das Evans Buch zu lesen - so vielleicht, dass meine Augen öffnet)

War es hilfreich?

Lösung

Martin Fowler hat viel über Domain-Modelle geschrieben, darunter anämischen Domänenmodelle . Er hat auch eine kurze Beschreibung (und UML-Klassendiagramme) der vielen Design-Muster für den Domain-Modelle und Datenbanken, die nützlich sein könnten: Katalog " Patterns of Enterprise Application Architecture ".

würde ich vorschlagen, an den Active Record und Data Mapper Muster. Aus der Beschreibung des Problems, es klingt wie Ihre Hilfsklassen beiden Domain / Geschäftsregeln enthalten und Datenbank Implementierungsdetails.

Die Active Record würden die Helfer Domänenlogik und Datenbank-Code in den anderen Domänenobjekte (wie Ihre Entity Basisklasse) bewegen. Der Data Mapper würden die Helfer Domänenlogik in die Domänenobjekte und der Datenbank-Code in einem separaten Kartenobjekt bewegen. Jeder Ansatz wäre objektorientierte als verfahrens Stil Hilfsklassen.

Eric Evans' "Domain Driven Design" Buch ist ausgezeichnet. Es wird ein bisschen trocken, aber es ist auf jeden Fall wert. InfoQ hat einen "Domain Driven Design schnell" Mini-Buch dass a gute Einführung in Evans' Buch. Plus "Domain Driven Design Schnell" ist als kostenloses PDF.

Andere Tipps

Um anämisch Modell zu vermeiden, Refactoring Ihrer Hilfsklassen:

Logik wie:
"Customer.PurchaseProduct (Produkt Produkt, Zahlung Zahlung)",
"Customer.KillCustomer (Person Killer, Waffe Waffe)"
sollten Sie rechts in die „Kunde“ Domain-Objekt vorhanden sind.

Logik wie:
"Customer.IsCustomerAlive ()"
"Customer.IsCustomerHappy ()"
gehen sollte Spezifikationen.

Logik wie:
"Customer.Create ()",
"Customer.Update ()"
offensichtlich sollte Repositories gehen.

Logik wie:
"Customer.SerializeInXml ()"
"Customer.GetSerializedCustomerSizeInBytes ()"
gehen zu den Dienstleistungen.

Komplexe Konstrukteure sollten Fabriken gehen.

Das ist, wie ich es sehe. Ich würde mich freuen, wenn jemand mein Verständnis von DDD Ansatz äußern könnte.


Edit:

Manchmal - anämischen Domänenmodell sollte nicht vermieden werden.

Edited meine Antwort hinzufügen, dass DDD nicht über das Aufnehmen und Ablegen Muster ist.
DDD ist über Art, wie wir denken.

Ich habe immer von dem anämischen Domänenmodell gedacht als ein Anti-Muster. Es ist klar, dass ein Kunde Produkte kaufen, kann diese Fähigkeit durch eine Interface-Implementierung generised wird

Interface IPurchase
      Purchase(Product);

, so dass ein jeder Ihrer Domain-Objekte kann dann die Umsetzung je nach Bedarf. Auf diese Weise können Sie die Funktionalität Ihrer Domain-Objekte einführen - was genau das ist, wo es sein sollte

.

Ein Ansatz, die Sie nicht erwähnt haben AOP verwendet Ihre Daten zugreifen zu handhaben. Ein Beispiel für meine letzte Verwendung dieses Ansatzes (obwohl für die Entsendung Zwecke stark vereinfacht) war, dass ich eine Account Domäne Entität hatte, die eine debit Methode hatte, erforderlich, um die Geschäftslogik einkapseln, um eine erfolgreiche Abbuchung vom Konto zu machen.

N. B. Der gesamte Code ist Java mit AspectJ AOP Notation ...

public boolean debit(int amount) {
    if (balance - amount >= 0) {
        balance = balance - amount;
        return true;
    }
    return false;
}

Mit dem entsprechenden Repository in meinem Aspekt injiziert, habe ich dann eine pointcut Aufrufe dieser Methode abfangen ...

pointcut debit(Account account,int amount) :
    execution(boolean Account.debit(int)) &&
    args(amount) &&
    target(account);

... und angewandter einige Ratschläge:

after(Account account, int amount) returning (boolean result)  : debit(account,amount) {
    if (result) getAccountRepository().debit(account, amount);
}

Meiner Meinung nach gibt eine schöne Trennung von Bedenken und ermöglicht Ihre Domain Einheiten vollständig auf der Geschäftslogik der Anwendung zu konzentrieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top