Rich vs Anemic Domain Model [geschlossen]

90

Ich entscheide, ob ich ein Rich-Domain-Modell anstelle eines anämischen Domain-Modells verwenden soll, und suche nach guten Beispielen für beide.

Ich habe Webanwendungen mithilfe eines anämischen Domänenmodells erstellt , das von einem Service -> Repository -> Speicherschichtsystem unterstützt wird, FluentValidation für die BL-Validierung verwendet und alle meine BL in die Service-Schicht eingefügt .

Ich habe Eric Evans DDD-Buch gelesen und er (zusammen mit Fowler und anderen) scheint zu glauben, dass anämische Domänenmodelle ein Anti-Muster sind.

Ich wollte nur wirklich einen Einblick in dieses Problem bekommen.

Außerdem suche ich wirklich nach einigen guten (grundlegenden) Beispielen für ein Rich-Domain-Modell und den Vorteilen gegenüber dem anämischen Domain-Modell, das es bietet.

Sam
quelle
Vielleicht möchten Sie auch diesen Blog
lesen, der
14
DDD> ADM , ADM> DDD , DDD> ADM , ADM> DDD , ADM + DDD ... DDD / ADM, oder wie man sich nicht über Software-Design einig ist !
sp00m
Hier ist ein Beispiel, wie man ein anämisches Domain-Modell vermeidet: medium.com/@wrong.about/…
Vadim Samokhin
9
Es ist lustig, dass diese Frage mit einem einzigen Link zu einem realen Projekt beantwortet werden konnte, das von einer realen Organisation finanziert wurde. Nach 5 Jahren keine gute Antwort, IMO. Reden ist billig. Zeig mir den Code.
Mateusz Stefek

Antworten:

56

Der Unterschied besteht darin, dass ein anämisches Modell Logik von Daten trennt. Die Logik wird häufig in Klassen eingeteilt genannt **Service, **Util, **Manager, **Helperund so weiter. Diese Klassen implementieren die Dateninterpretationslogik und nehmen daher das Datenmodell als Argument. Z.B

public BigDecimal calculateTotal(Order order){
...
}

Der Rich-Domain-Ansatz kehrt dies um, indem die Dateninterpretationslogik in das Rich-Domain-Modell eingefügt wird. Auf diese Weise werden Logik und Daten zusammengefügt, und ein umfangreiches Domänenmodell würde folgendermaßen aussehen:

order.getTotal();

Dies hat einen großen Einfluss auf die Objektkonsistenz. Da die Dateninterpretationslogik die Daten umschließt (auf Daten kann nur über Objektmethoden zugegriffen werden), können die Methoden auf Zustandsänderungen anderer Daten reagieren -> Dies nennen wir Verhalten.

In einem anämischen Modell können die Datenmodelle nicht garantieren, dass sie sich in einem Rechtszustand befinden, während dies in einem Rich-Domain-Modell möglich ist. Ein reichhaltiges Domänenmodell wendet OO-Prinzipien wie Kapselung, Verstecken von Informationen und Zusammenführen von Daten und Logik an. Daher ist ein anämisches Modell aus OO-Sicht ein Anti-Muster.

Weitere Informationen finden Sie in meinem Blog unter https://www.link-intersystems.com/blog/2011/10/01/anemic-vs-rich-domain-models/.

René Link
quelle
15
Angenommen, die Berechnung des Gesamtpreises einer Bestellung umfasst Folgendes: 1) Einen Rabatt gewähren, der davon abhängt, ob der Kunde Mitglied eines der vielen möglichen Treueprogramme ist. 2) Anwenden eines Rabatts für Bestellungen, die eine bestimmte Artikelgruppe enthalten, abhängig von der aktuellen Marketingkampagne des Geschäfts. 3) Berechnung der Steuer, wenn die Höhe der Steuer von der jeweiligen Position abhängt. Wo würde Ihrer Meinung nach all diese Logik hingehören? Könnten Sie bitte ein einfaches Pseudocode-Beispiel geben? Danke dir!
Nik
4
@Nik Im Rich-Modell hätte die Bestellung einen Verweis auf das Kundenobjekt und das Kundenobjekt einen Verweis auf das Treueprogramm. Somit hätte der Auftrag Zugriff auf alle benötigten Informationen, ohne dass explizite Verweise auf Dinge wie Dienste und Repositorys erforderlich wären, aus denen diese Informationen abgerufen werden könnten. Es scheint jedoch leicht zu sein, auf einen Fall zu stoßen, in dem zyklische Referenzen stattfinden. Dh Auftragsreferenzen Kunde, Kunde hat eine Liste aller Bestellungen. Ich denke, dies kann teilweise der Grund sein, warum die Leute jetzt Anemic bevorzugen.
Crush
3
@crush Der von Ihnen beschriebene Ansatz funktioniert sehr gut. Es gibt einen Haken. Wahrscheinlich speichern wir die Entitäten in einer Datenbank. Um die Gesamtsumme einer Bestellung zu berechnen, müssen wir die Tabelle Bestellung, Kunde, Treueprogramm, Marketingkampagne und Steuern aus der Datenbank abrufen. Bedenken Sie auch, dass ein Kunde eine Sammlung von Bestellungen hat, ein Treueprogramm eine Sammlung von Kunden und so weiter. Wenn wir all dies naiv abrufen, wird am Ende die gesamte Datenbank in den RAM geladen. Dies ist natürlich nicht realisierbar, daher laden wir nur relevante Daten aus der DB ... 1/2
Nik
3
@Nik "Wenn wir alle diese Daten nativ abrufen, wird am Ende die gesamte Datenbank in den RAM geladen." Das ist auch einer der Hauptnachteile des reichen Modells in meinem Kopf. Das Rich-Modell ist so lange nützlich, bis Ihre Domain groß und komplex wird und Sie dann auf Infrastrukturbeschränkungen stoßen. Hier können jedoch ORMs mit verzögertem Laden eingesetzt werden, um zu helfen. Wenn Sie ein gutes Modell finden, können Sie umfangreiche Modelle beibehalten, ohne die gesamte Datenbank in den Speicher zu laden, wenn Sie nur 1/20 davon benötigen. Trotzdem neige ich dazu, das anämische Modell mit CQRS selbst zu verwenden, nachdem ich jahrelang zwischen anämisch und reich hin und her gewechselt bin.
Crush
2
Eine andere zu berücksichtigende Sache ist, wo Ihre Geschäftsdomänenlogik lebt. Immer mehr Entwickler verschieben es aus der Datenbank in die Anwendungen, in die es meiner Meinung nach gehört. Wenn Sie jedoch in einer Situation stecken bleiben, in der Ihr Unternehmen verlangt, dass die Geschäftslogik in der Datenbankebene verbleibt (gespeicherte Prozeduren), profitieren Sie mit ziemlicher Sicherheit nicht davon, diese Logik auch in ein umfangreiches Domänenmodell aufzunehmen. Tatsächlich könnten Sie sich gerade darauf einstellen, in Konflikte zu geraten, in denen die gespeicherten Prozeduren andere Regeln haben als die Domänenschicht Ihrer Anwendung ...
Crush
53

Bozhidar Bozhanov scheint in diesem Blog-Beitrag für das anämische Modell zu argumentieren .

Hier ist die Zusammenfassung, die er präsentiert:

  • Domänenobjekte sollten nicht im Frühjahr (IoC) verwaltet werden, sie sollten keine DAOs oder irgendetwas im Zusammenhang mit der Infrastruktur enthalten

  • Domänenobjekte haben die Domänenobjekte, von denen sie abhängen, durch den Ruhezustand (oder den Persistenzmechanismus) festgelegt.

  • Domänenobjekte führen die Geschäftslogik aus, wie es die Kernidee von DDD ist, dies schließt jedoch keine Datenbankabfragen oder CRUD-Operationen für den internen Status des Objekts ein

  • DTOs werden selten benötigt - die Domänenobjekte sind in den meisten Fällen die DTOs selbst (wodurch etwas Boilerplate-Code gespeichert wird).

  • Dienste führen CRUD-Operationen aus, senden E-Mails, koordinieren die Domänenobjekte, generieren Berichte basierend auf mehreren Domänenobjekten, führen Abfragen aus usw.

  • Die Service- (Anwendungs-) Schicht ist nicht so dünn, enthält jedoch keine Geschäftsregeln, die den Domänenobjekten eigen sind

  • Codegenerierung sollte vermieden werden. Abstraktion, Entwurfsmuster und DI sollten verwendet werden, um die Notwendigkeit der Codegenerierung zu überwinden und letztendlich die Codeduplizierung zu beseitigen.

AKTUALISIEREN

Ich habe kürzlich diesen Artikel gelesen, in dem der Autor befürwortet, einen hybriden Ansatz zu verfolgen - Domänenobjekte können verschiedene Fragen nur aufgrund ihres Zustands beantworten (was im Fall von vollständig anämischen Modellen wahrscheinlich in der Serviceschicht geschehen würde).

geoand
quelle
11
Ich kann aus diesem Artikel nicht entnehmen, dass Bozho für das anämische Domänenmodell zu argumentieren scheint. Die Service- (Anwendungs-) Schicht ist nicht so dünn, enthält jedoch keine Geschäftsregeln, die den Domänenobjekten eigen sind . Ich verstehe, dass Domänenobjekte die ihnen innewohnende Geschäftslogik enthalten sollten, aber keine andere Infrastrukturlogik . Dieser Ansatz scheint mir überhaupt kein anämisches Domänenmodell zu sein.
Utku
8
Auch dieses: Domänenobjekte führen die Geschäftslogik aus, wie es die Kernidee von DDD ist, aber dies beinhaltet keine Datenbankabfragen oder CRUD-only-Operationen für den internen Status des Objekts . Diese Aussagen scheinen das anämische Domänenmodell überhaupt nicht zu begünstigen. Sie geben nur an, dass die Infrastrukturlogik nicht an Domänenobjekte gekoppelt werden sollte. Zumindest verstehe ich das so.
Utku
@Utku Meiner Ansicht nach scheint es ziemlich klar zu sein, dass Bozho eine Art Hybrid zwischen den beiden Modellen befürwortet, ein Hybrid, von dem ich sagen würde, dass er dem anämischen Modell näher ist als dem reichen Modell.
Geo und
40

Mein Standpunkt ist folgender:

Anämisches Domänenmodell = Datenbanktabellen, die Objekten zugeordnet sind (nur Feldwerte, kein reales Verhalten)

Rich Domain Model = Eine Sammlung von Objekten, die das Verhalten offenlegen

Wenn Sie eine einfache CRUD-Anwendung erstellen möchten, reicht möglicherweise ein anämisches Modell mit einem klassischen MVC-Framework aus. Wenn Sie jedoch eine Art Logik implementieren möchten, bedeutet ein anämisches Modell, dass Sie keine objektorientierte Programmierung durchführen.

* Beachten Sie, dass das Objektverhalten nichts mit Persistenz zu tun hat. Eine andere Ebene (Datenmapper, Repositorys usw.) ist für die Persistenz von Domänenobjekten verantwortlich.

George
quelle
5
Entschuldigen Sie meine Unwissenheit, aber wie kann ein Rich-Domain-Modell dem SOLID-Prinzip folgen, wenn Sie die gesamte Entity-bezogene Logik in die Klasse einfügen. Dies verstößt gegen das SOLID-Prinzip, das 'S' genau, das für einzelne Verantwortung steht und besagt, dass eine Klasse nur eines tun und es richtig machen sollte.
Redigaffi
5
@redigaffi Es hängt davon ab, wie Sie "eine Sache" definieren. Betrachten wir eine Klasse mit zwei Eigenschaften und zwei Methoden: x, y, sumund difference. Das sind vier Dinge. Oder Sie könnten argumentieren, es ist Addition und Subtraktion (zwei Dinge). Oder Sie könnten argumentieren, dass es Mathe ist (eine Sache). Es gibt viele Blog-Beiträge darüber, wie Sie bei der Anwendung von SRP ein Gleichgewicht finden. Hier ist eine: hackernoon.com/...
Rainbolt
2
In DDD bedeutet Einzelverantwortlichkeit, dass eine Klasse / ein Modell ihren eigenen Status verwalten kann, ohne dass der Rest des gesamten Systems Nebenwirkungen hat. Jede andere Definition führt meiner Erfahrung nach nur zu langwierigen philosophischen Debatten.
ZombieTfk
12

Zunächst habe ich die Antwort aus diesem Artikel http://msdn.microsoft.com/en-gb/magazine/dn385704.aspx kopiert und eingefügt

Abbildung 1 zeigt ein anämisches Domänenmodell, bei dem es sich im Grunde um ein Schema mit Gettern und Setzern handelt.

Figure 1 Typical Anemic Domain Model Classes Look Like Database Tables

public class Customer : Person
{
  public Customer()
  {
    Orders = new List<Order>();
  }
  public ICollection<Order> Orders { get; set; }
  public string SalesPersonId { get; set; }
  public ShippingAddress ShippingAddress { get; set; }
}
public abstract class Person
{
  public int Id { get; set; }
  public string Title { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string CompanyName { get; set; }
  public string EmailAddress { get; set; }
  public string Phone { get; set; }
}

In diesem umfassenderen Modell besteht die öffentliche Oberfläche des Kunden aus expliziten Methoden, anstatt nur Eigenschaften zum Lesen und Schreiben bereitzustellen.

Figure 2 A Customer Type That’s a Rich Domain Model, Not Simply Properties

public class Customer : Contact
{
  public Customer(string firstName, string lastName, string email)
  {
    FullName = new FullName(firstName, lastName);
    EmailAddress = email;
    Status = CustomerStatus.Silver;
  }
  internal Customer()
  {
  }
  public void UseBillingAddressForShippingAddress()
  {
    ShippingAddress = new Address(
      BillingAddress.Street1, BillingAddress.Street2,
      BillingAddress.City, BillingAddress.Region,
      BillingAddress.Country, BillingAddress.PostalCode);
  }
  public void CreateNewShippingAddress(string street1, string street2,
   string city, string region, string country, string postalCode)
  {
    ShippingAddress = new Address(
      street1,street2,
      city,region,
      country,postalCode)
  }
  public void CreateBillingInformation(string street1,string street2,
   string city,string region,string country, string postalCode,
   string creditcardNumber, string bankName)
  {
    BillingAddress = new Address      (street1,street2, city,region,country,postalCode );
    CreditCard = new CustomerCreditCard (bankName, creditcardNumber );
  }
  public void SetCustomerContactDetails
   (string email, string phone, string companyName)
  {
    EmailAddress = email;
    Phone = phone;
    CompanyName = companyName;
  }
  public string SalesPersonId { get; private set; }
  public CustomerStatus Status { get; private set; }
  public Address ShippingAddress { get; private set; }
  public Address BillingAddress { get; private set; }
  public CustomerCreditCard CreditCard { get; private set; }
}
Razan Paul
quelle
2
Es gibt ein Problem mit Methoden, die sowohl ein Objekt erstellen als auch eine Eigenschaft mit neu erstelltem Objekt zuweisen. Sie machen Code weniger erweiterbar und flexibel. 1) Was ist, wenn der Code-Konsument nicht mehrere zusätzliche Eigenschaften erstellen möchte Address, sondern von diesen ExtendedAddressgeerbt wird Address? 2) Oder CustomerCreditCardKonstruktorparameter ändern , um BankIDstatt zu nehmen BankName?
Lightman
Was zum Erstellen einer Adresse erfordert zusätzliche Dienste als das Objekt? Sie müssen die Methode injizieren, um diese Dienste zu erhalten. Was ist, wenn es viele Dienstleistungen sind?
Crush
8

Als ich monolithische Desktop-Apps schrieb, erstellte ich umfangreiche Domänenmodelle, mit denen ich Spaß daran hatte, sie zu erstellen.

Jetzt schreibe ich winzige HTTP-Microservices, es gibt so wenig Code wie möglich, einschließlich anämischer DTOs.

Ich denke, DDD und dieses anämische Argument stammen aus der Zeit der monolithischen Desktop- oder Server-Apps. Ich erinnere mich an diese Zeit und würde zustimmen, dass anämische Modelle seltsam sind. Ich habe eine große monolithische FX-Handels-App erstellt und es gab kein Modell, wirklich, es war schrecklich.

Bei Microservices sind die kleinen Services mit ihrem reichhaltigen Verhalten wohl die zusammensetzbaren Modelle und Aggregate innerhalb einer Domäne. Daher erfordern die Microservice-Implementierungen selbst möglicherweise keine weitere DDD. Die Microservice-Anwendung kann die Domäne sein.

Ein Auftragsmikroservice kann nur sehr wenige Funktionen haben, die als RESTful-Ressourcen oder über SOAP oder was auch immer ausgedrückt werden. Der Mikroservice-Code für Bestellungen kann sehr einfach sein.

Ein größerer monolithischerer einzelner (Mikro-) Dienst, insbesondere ein Dienst, der das Modell im RAM hält, kann von DDD profitieren.

Luke Puplett
quelle
Haben Sie Codebeispiele für HTTP-Mikrodienste, die Ihren aktuellen Stand der Technik darstellen? Bitten Sie Sie nicht, etwas aufzuschreiben, sondern teilen Sie nur Links, wenn Sie etwas haben, auf das Sie hinweisen könnten. Vielen Dank.
Casey Plummer
7

Einer der Vorteile von Rich Domain-Klassen besteht darin, dass Sie ihr Verhalten (Methoden) jedes Mal aufrufen können, wenn Sie den Verweis auf das Objekt in einer beliebigen Ebene haben. Außerdem neigen Sie dazu, kleine und verteilte Methoden zu schreiben, die zusammenarbeiten. In anämischen Domänenklassen neigen Sie dazu, fette Verfahrensmethoden (in der Serviceschicht) zu schreiben, die normalerweise vom Anwendungsfall abhängen. Sie sind im Vergleich zu Rich-Domain-Klassen normalerweise weniger wartbar.

Ein Beispiel für Domänenklassen mit Verhalten:

class Order {

     String number

     List<OrderItem> items

     ItemList bonus

     Delivery delivery

     void addItem(Item item) { // add bonus if necessary }

     ItemList needToDeliver() { // items + bonus }

     void deliver() {
         delivery = new Delivery()
         delivery.items = needToDeliver()
     }

}

Die Methode needToDeliver()gibt eine Liste der Artikel zurück, die geliefert werden müssen, einschließlich Bonus. Es kann innerhalb der Klasse, von einer anderen verwandten Klasse oder von einer anderen Ebene aufgerufen werden. Wenn Sie beispielsweise Orderzur Ansicht übergehen , können Sie mit needToDeliver()ausgewählt Orderdie Liste der Elemente anzeigen, die vom Benutzer bestätigt werden sollen, bevor er auf die Schaltfläche Speichern klickt, um die Anzeige beizubehalten Order.

Auf Kommentar antworten

So verwende ich die Domänenklasse vom Controller:

def save = {
   Order order = new Order()
   order.addItem(new Item())
   order.addItem(new Item())
   repository.create(order)
}

Die Erstellung von Orderund seine LineItemist in einer Transaktion. Wenn einer der LineItemnicht erstellt werden kann, wird kein Ordererstellt.

Ich neige dazu, Methoden zu haben, die eine einzelne Transaktion darstellen, wie zum Beispiel:

def deliver = {
   Order order = repository.findOrderByNumber('ORDER-1')
   order.deliver()       
   // save order if necessary
}

Alles, was sich darin befindet, deliver()wird als eine einzige Transaktion ausgeführt. Wenn ich viele nicht verwandte Methoden in einer einzigen Transaktion ausführen muss, würde ich eine Serviceklasse erstellen.

Um eine verzögerte Ladeausnahme zu vermeiden, verwende ich JPA 2.1 mit dem Namen Entity Graph. Im Bildschirm "Controller für Zustellung" kann ich beispielsweise eine Methode zum Laden von deliveryAttributen und zum Ignorieren erstellen bonus, z repository.findOrderByNumberFetchDelivery(). Im Bonusbildschirm rufe ich eine andere Methode auf, die bonusAttribute lädt und ignoriert delivery, z repository.findOrderByNumberFetchBonus(). Dies erfordert Disziplin, da ich immer noch nicht deliver()im Bonusbildschirm anrufen kann .

Jocki
quelle
1
Wie wäre es mit dem Transaktionsumfang?
Kboom
5
Das Verhalten des Domänenmodells sollte keine Persistenzlogik (einschließlich Transaktion) enthalten. Sie sollten (im Unit-Test) testbar sein, ohne mit der Datenbank verbunden zu sein. Der Transaktionsumfang liegt in der Verantwortung der Service- oder Persistenzschicht.
Jocki
1
Wie wäre es dann mit Lazy-Loading?
Kboom
Wenn Sie im Komponententest Domänenklasseninstanzen erstellen, befinden sie sich nicht im verwalteten Zustand, da es sich um einfache Objekte handelt. Alle Verhaltensweisen können ordnungsgemäß getestet werden.
Jocki
Und was passiert, wenn Sie das Domänenobjekt von der Serviceschicht erwarten? Wird es dann nicht geschafft?
Kboom
2

Ich denke, die Wurzel des Problems liegt in der falschen Zweiteilung. Wie ist es möglich, diese beiden Modelle zu extrahieren: reich und "anämisch" und sie einander gegenüberzustellen? Ich denke, es ist nur möglich, wenn Sie falsche Vorstellungen darüber haben, was eine Klasse ist . Ich bin mir nicht sicher, aber ich glaube, ich habe es in einem von Bozhidar Bozhanov-Videos auf Youtube gefunden. Eine Klasse ist keine Daten + Methode über diese Daten. Es ist ein völlig ungültiges Verständnis, das zur Unterteilung von Klassen in zwei Kategorien führt: nur Daten, also anämisches Modell und Daten + Methoden - so reichhaltiges Modell (genauer gesagt gibt es eine dritte Kategorie: nur Methoden gerade).

Die Wahrheit ist, dass Klasse ein Konzept in einem ontologischen Modell ist, ein Wort, eine Definition, ein Begriff, eine Idee, es ist ein DENOTAT . Und dieses Verständnis beseitigt falsche Dichotomie: Sie können kein NUR anämisches Modell oder NUR ein reichhaltiges Modell haben, da dies bedeutet, dass Ihr Modell nicht angemessen und für die Realität nicht relevant ist: Einige Konzepte enthalten nur Daten, einige nur Methoden, andere von ihnen sind gemischt. Da wir in diesem Fall versuchen, einige Kategorien, Objektmengen, Beziehungen, Konzepte mit Klassen zu beschreiben, und wie wir wissen, sind einige Konzepte nur Prozesse (Methoden), einige nur Attribute (Daten), andere Sie sind Beziehungen zu Attributen (gemischt).

Ich denke, eine adäquate Anwendung sollte alle Arten von Klassen umfassen und vermeiden, sich fanatisch auf nur ein Modell zu beschränken. Egal, wie die Logik dargestellt wird: mit Code oder mit interpretierbaren Datenobjekten (wie Free Monads ): Wir sollten Klassen (Konzepte, Denotate) haben, die Prozesse, Logik, Beziehungen, Attribute, Merkmale, Daten usw. darstellen und nicht zu versuchen, einige von ihnen zu vermeiden oder sie alle auf die eine Art zu reduzieren.

Wir können also Logik in eine andere Klasse extrahieren und Daten in der ursprünglichen Klasse belassen, aber es hat keinen Sinn, da ein Konzept Attribute und Beziehungen / Prozesse / Methoden enthalten kann und eine Trennung von ihnen das Konzept unter zwei Namen dupliziert, die sein können reduziert auf Muster: "OBJECT-Attribute" und "OBJECT-Logic". In prozeduralen und funktionalen Sprachen ist es aufgrund ihrer Einschränkung in Ordnung, aber es ist eine übermäßige Selbstbeherrschung für eine Sprache, mit der Sie alle Arten von Konzepten beschreiben können.

Paul-AG
quelle
0

Anämische Domänenmodelle sind wichtig für ORM und die einfache Übertragung über Netzwerke (das Lebenselixier aller kommerziellen Anwendungen). OO ist jedoch sehr wichtig für die Kapselung und Vereinfachung der Transaktions- / Handhabungsteile Ihres Codes.

Daher ist es wichtig, sich von einer Welt in die andere identifizieren und konvertieren zu können.

Benennen Sie Anemic-Modelle wie AnemicUser oder UserDAO usw., damit Entwickler wissen, dass es eine bessere Klasse gibt, und verwenden Sie dann einen geeigneten Konstruktor für die Klasse None Anemic

User(AnemicUser au)

und Adaptermethode zum Erstellen der anämischen Klasse für Transport / Persistenz

User::ToAnemicUser() 

Verwenden Sie den nicht anämischen Benutzer überall außerhalb von Transport / Persistenz

Andrew Pate
quelle
-1

Hier ist ein Beispiel, das helfen könnte:

Anämisch

class Box
{
    public int Height { get; set; }
    public int Width { get; set; }
}

Nicht anämisch

class Box
{
    public int Height { get; private set; }
    public int Width { get; private set; }

    public Box(int height, int width)
    {
        if (height <= 0) {
            throw new ArgumentOutOfRangeException(nameof(height));
        }
        if (width <= 0) {
            throw new ArgumentOutOfRangeException(nameof(width));
        }
        Height = height;
        Width = width;
    }

    public int area()
    {
       return Height * Width;
    }
}
Alireza Rahmani Khalili
quelle
Dies sieht so aus, als ob es in ein ValueObject gegen eine Entität konvertiert werden kann.
Code5
Nur eine Kopie aus Wikipedia ohne Erklärung
einfügen
Wer hat früher geschrieben? @wst
Alireza Rahmani Khalili
@AlirezaRahmaniKhalili Laut Wikipedia-Geschichte waren sie die Ersten ... Es sei denn, ich habe Ihre Frage nicht verstanden.
27.
-1

Der klassische Ansatz für DDD besagt nicht, dass Anemic vs Rich Models um jeden Preis vermieden werden müssen. MDA kann jedoch weiterhin alle DDD-Konzepte (begrenzte Kontexte, Kontextzuordnungen, Wertobjekte usw.) anwenden, jedoch in allen Fällen Anemic vs Rich-Modelle verwenden. Es gibt viele Fälle, in denen die Verwendung von Domänendiensten zum Orchestrieren komplexer Domänennutzungsfälle über eine Reihe von Domänenaggregaten hinweg ein viel besserer Ansatz ist als nur das Aufrufen von Aggregaten aus der Anwendungsschicht. Der einzige Unterschied zum klassischen DDD-Ansatz besteht darin, wo sich alle Validierungen und Geschäftsregeln befinden. Es gibt ein neues Konstrukt, das als Modellvalidatoren bekannt ist. Validatoren stellen die Integrität des vollständigen Eingabemodells sicher, bevor ein Anwendungsfall oder ein Domänenworkflow stattfindet. Die aggregierten Root- und untergeordneten Entitäten sind anämisch, aber jede kann bei Bedarf ihre eigenen Modellvalidatoren aufrufen. durch seinen Root-Validator. Validatoren, die sich immer noch an SRP halten, sind leicht zu warten und können in Einheiten überprüft werden.

Der Grund für diese Verschiebung ist, dass wir uns jetzt mehr auf eine API als auf einen UX-Ansatz für Microservices konzentrieren. REST hat dabei eine sehr wichtige Rolle gespielt. Der traditionelle API-Ansatz (aufgrund von SOAP) wurde ursprünglich auf eine befehlsbasierte API im Vergleich zu HTTP-Verben (POST, PUT, PATCH, GET und DELETE) festgelegt. Eine befehlsbasierte API passt gut zum objektorientierten Ansatz von Rich Model und ist immer noch sehr gültig. Einfache CRUD-basierte APIs eignen sich zwar viel besser in ein Rich-Modell, eignen sich jedoch viel besser für einfache anämische Modelle, Validatoren und Domänendienste, um den Rest zu koordinieren.

Ich liebe DDD in allem, was es zu bieten hat, aber irgendwann muss man es ein wenig dehnen, um sich an die sich ständig ändernde und bessere Herangehensweise an die Architektur anzupassen.

Code5
quelle