381 Stimmen

Domain Driven Design: Domänendienst, Anwendungsdienst

Kann mir jemand den Unterschied zwischen Domain- und Anwendungsdiensten erklären, indem er einige Beispiele gibt? Und wenn ein Dienst ein Domänendienst ist, würde ich die tatsächliche Implementierung dieses Dienstes im Domänen-Assembly platzieren und wenn ja, würde ich auch Repositories in diesen Domänendienst einfügen? Einige Informationen wären wirklich hilfreich.

0 Stimmen

Fühlen Sie sich frei, dies zu überprüfen: youtu.be/MfEpw2WXXyk

525voto

Vijay Patel Punkte 16000

Dienste gibt es in 3 Varianten: Domänendienste, Anwendungsdienste und Infrastrukturdienste.

  • Domänendienste: Enthält Geschäftslogik, die nicht natürlicherweise zu einem Domänenobjekt passt und sind NICHT typische CRUD-Operationen – diese würden zu einem Repository gehören.
  • Anwendungsdienste: Werden von externen Benutzern verwendet, um mit Ihrem System zu kommunizieren (denken Sie an Webdienste). Wenn Benutzer Zugriff auf CRUD-Operationen benötigen, würden sie hier freigegeben.
  • Infrastrukturdienste: Wird verwendet, um technische Aspekte (z.B. MSMQ, E-Mail-Anbieter usw.) zu abstrahieren.

Es ist sinnvoll, Domänendienste zusammen mit Ihren Domänenobjekten zu behalten – sie konzentrieren sich alle auf die Domänenlogik. Und ja, Sie können Repositories in Ihre Dienste einfügen.

Anwendungsdienste werden in der Regel sowohl Domänendienste als auch Repositories verwenden, um externe Anfragen zu bearbeiten.

6 Stimmen

Wo würden Sie die Befehle und Abfragen von CQRS platzieren? Welcher Dienst generiert sie und welcher Dienst behandelt sie?

20 Stimmen

Ich denke, dass Anwendungsdienste unabhängig von technischen Details wie "Webdiensten" sein sollten, die von solchen Diensten verwendet werden. Siehe Dienste im domänengesteuerten Entwurf

3 Stimmen

Denken Sie zweimal nach, bevor Sie irgendwelche Arten von Service-Klassen verwenden. Chancen stehen gut, dass Sie auch ohne sie auskommen können und Ihr Code letztendlich viel klarer und wartbarer wird.

143voto

Niels van der Rest Punkte 30365

(Wenn Sie keine Lust zum Lesen haben, gibt es eine Zusammenfassung am Ende :-)

Auch ich habe mit der genauen Definition von Anwendungsdiensten gerungen. Obwohl Vijays Antwort vor einem Monat sehr hilfreich für meinen Denkprozess war, bin ich jetzt mit einem Teil davon nicht einverstanden.

Weitere Ressourcen

Es gibt nur sehr wenige Informationen über Anwendungsdienste. Themen wie Aggregate Roots, Repositories und Domänendienste werden ausführlich diskutiert, aber Anwendungsdienste werden entweder nur kurz erwähnt oder ganz ausgelassen.

Der MSDN Magazine-Artikel Einführung in das domänengesteuerte Design beschreibt Anwendungsdienste als eine Möglichkeit, Ihr Domänenmodell für externe Clients zu transformieren und/oder freizugeben, z. B. als WCF-Dienst. So beschreibt auch Vijay Anwendungsdienste. Aus dieser Sicht sind Anwendungsdienste eine Schnittstelle zu Ihrer Domäne.

Jeffrey Palermos Artikel zur Onion-Architektur (Teil eins, zwei und drei) sind lesenswert. Er behandelt Anwendungsdienste als Anwendungsebenenkonzepte, wie z. B. eine Benutzersitzung. Obwohl dies meiner Vorstellung von Anwendungsdiensten näher kommt, entspricht es immer noch nicht meinen Gedanken zu diesem Thema.

Meine Gedanken

Ich denke inzwischen an Anwendungsdienste als Abhängigkeiten, die von der Anwendung bereitgestellt werden. In diesem Fall könnte die Anwendung eine Desktopanwendung oder ein WCF-Dienst sein.

Domäne

Zeit für ein Beispiel. Sie starten mit Ihrer Domäne. Alle Entitäten und alle Domänendienste, die nicht von externen Ressourcen abhängen, sind hier implementiert. Alle Domänenkonzepte, die von externen Ressourcen abhängen, werden über eine Schnittstelle definiert. Hier ist eine mögliche Lösungsstruktur (Projektname in fett):

Meine Lösung
- **Mein.Produkt.Kern** (My.Product.dll)
  - Domänendienste
      IWechselkursdienst
    Produkt
    Produktfabrik
    IProduktrepository

Die Klassen Produkt und Produktfabrik wurden im Kern-Assembly implementiert. Das IProduktrepository wird wahrscheinlich von einer Datenbank unterstützt. Die Implementierung davon geht die Domäne nichts an und wird daher durch eine Schnittstelle definiert.

Fürs Erste konzentrieren wir uns auf den IWechselkursdienst. Die Geschäftslogik dieses Dienstes wird von einem externen Webservice implementiert. Sein Konzept gehört jedoch immer noch zur Domäne und wird durch diese Schnittstelle repräsentiert.

Infrastruktur

Die Implementierung der externen Abhängigkeiten ist Teil der Anwendungsinfrastruktur:

Meine Lösung
+ **Mein.Produkt.Kern** (My.Product.dll)
- **Mein.Produkt.Infrastruktur** (My.Product.Infrastructure.dll)
  - Domänendienste
      XEWechselkursdienst
    SqlServerProduktrepository

XEWechselkursdienst implementiert den Domaindienst IWechselkursdienst, indem er mit xe.com kommuniziert. Diese Implementierung kann von Anwendungen genutzt werden, die Ihr Domänenmodell verwenden, indem sie das Infrastruktur-Assembly einschließen.

Anwendung

Beachten Sie, dass ich noch nicht über Anwendungsdienste gesprochen habe. Wir werden uns diese jetzt ansehen. Angenommen, wir möchten eine IWechselkursdienst-Implementierung bereitstellen, die einen Cache für schnelle Nachschlagen verwendet. Der Umriss dieser Dekoratorklasse könnte so aussehen.

public class CachingWechselkursdienst : IWechselkursdienst
{
    private IWechselkursdienst dienst;
    private ICache cache;

    public CachingWechselkursdienst(IWechselkursdienst dienst, ICache cache)
    {
        this.dienst = dienst;
        this.cache = cache;
    }

    // Implementierung, die den bereitgestellten Dienst und Cache nutzt.
}

Bemerken Sie den ICache-Parameter? Dieses Konzept gehört nicht zu unserer Domäne, daher ist es kein Domänendienst. Es ist ein Anwendungsdienst. Es ist eine Abhängigkeit unserer Infrastruktur, die von der Anwendung bereitgestellt werden kann. Lassen Sie uns eine Anwendung einführen, die dies zeigt:

Meine Lösung
- **Mein.Produkt.Kern** (My.Product.dll)
  - Domänendienste
      IWechselkursdienst
    Produkt
    Produktfabrik
    IProduktrepository
- **Mein.Produkt.Infrastruktur** (My.Product.Infrastructure.dll)
  - Anwendungsdienste
      ICache
  - Domänendienste
      CachingWechselkursdienst
      XEWechselkursdienst
    SqlServerProduktrepository
- **Mein.Produkt.WcfService** (My.Product.WcfService.dll)
  - Anwendungsdienste
      MemcachedCache
    IMyWcfService.cs
  + MyWcfService.svc
  + Web.config

All dies kommt in der Anwendung wie folgt zusammen:

// Richten Sie alle Abhängigkeiten ein und registrieren Sie sie im IoC-Behälter.
var dienst = new XEWechselkursdienst();
var cache = new MemcachedCache();
var cachingDienst = new CachingWechselkursdienst(dienst, cache);

ServiceLocator.For().Use(cachingDienst);

Zusammenfassung

Ein vollständige Anwendung besteht aus drei Hauptebenen:

  • Domäne
  • Infrastruktur
  • Anwendung

Die Domänenschicht enthält die Domänenentitäten und eigenständigen Domänendienste. Alle domänenbezogenen Konzepte (dazu gehören Domänendienste, aber auch Repositories), die von externen Ressourcen abhängen, werden über Schnittstellen definiert.

Die Infrastrukturschicht enthält die Implementierung der Schnittstellen aus der Domänenschicht. Diese Implementierungen können neue nicht-domänenbezogene Abhängigkeiten einführen, die von der Anwendung bereitgestellt werden müssen. Dies sind die Anwendungsdienste und werden über Schnittstellen repräsentiert.

Die Anwendungsschicht enthält die Implementierung der Anwendungsdienste. Die Anwendungsschicht kann auch zusätzliche Implementierungen von Domänenschnittstellen enthalten, wenn die Implementierungen aus der Infrastrukturschicht nicht ausreichen.

Obwohl diese Perspektive möglicherweise nicht mit der allgemeinen Definition von DDD-Diensten übereinstimmt, trennt sie die Domäne von der Anwendung und ermöglicht es Ihnen, das Domänen- (und Infrastruktur-)Assembly zwischen mehreren Anwendungen zu teilen.

0 Stimmen

Vielen Dank für das Teilen Ihrer Gedanken, aber ich habe eine Frage. Wie erstelle ich einen IDomainService, bei dem eine Methode Daten vom Controller (MVC) verwendet? Angenommen, wir haben eine Controller-Methode Save(RequestModel model). RequestModel gehört zur UI und nicht zur Domänenschicht. Wie soll ich die Daten an unseren Dienst übergeben? Ich kann nicht einfach IDomainService.Save(model) machen.

3 Stimmen

@dario-g: Sie müssten Ihr Domain-Modell aus dem Anforderungsmodell rekonstruieren/neu erstellen und das Domain-Modell an den Domain-Dienst übergeben. Diese Frage könnte Ihnen einige Ideen bieten. Wenn nicht, lassen Sie es mich wissen und ich werde sehen, ob ich einige Zeit habe, um eine Antwort auf die andere Frage hinzuzufügen.

0 Stimmen

Die vorgeschlagene Frage ist nicht besonders gut. Sehr oft müssen Sie bestimmte Aktionen auf einem Domänenobjekt ausführen. Es bedeutet nicht einfach nur Werte von einem Objekt ins andere zu kopieren. Noch schlimmer, wenn Sie dies bei verschiedenen Domänenobjekten tun müssen. Also, ich bin gespannt ... Schauen Sie sich das an: lostechies.com/blogs/jimmy_bogard/archive/2009/09/17/…

70voto

Ghola Punkte 728

Die beste Ressource, die mir geholfen hat, den Unterschied zwischen einem Anwendungsdienst und einem Domänendienst zu verstehen, war die Java-Implementierung von Eric Evans' Cargo-Beispiel, das hier gefunden wurde. Wenn Sie es herunterladen, können Sie sich die Interna von RoutingService (ein Domänendienst) und den Application Services BookingService und CargoInspectionService ansehen.

Mein 'Aha'-Moment wurde durch zwei Dinge ausgelöst:

  • Das Lesen der Beschreibung der Dienste im obigen Link, genauer gesagt dieser Satz:

Domänendienste werden in Bezug auf die ubiquitäre Sprache und die Domänenarten ausgedrückt, d.h. die Methodenargumente und die Rückgabewerte sind geeignete Domänenklassen.

Was mir sehr hilft, Äpfel von Orangen zu trennen, ist das Denken in Bezug auf Anwendungsworkflows. Alle Logik, die den Anwendungsworkflow betrifft, endet typischerweise als Application Services, die in die Anwendungsschicht eingebettet sind, während Konzepte aus der Domäne, die nicht als Modellobjekte erscheinen, ein oder mehrere Domänendienste bilden.

5 Stimmen

Ich stimme zu, das ist genau meine Definition von Anwendungsdiensten und es passt zu allen Situationen, die ich bisher getroffen habe. Domänendienste behandeln alles, was mit Domänenobjekten zu tun hat, aber über den Umfang einer einzelnen Entität hinausgeht. Bsp: BookReferencesService.GetNextAvailableUniqueTrackingNumber(), der Fokus liegt eindeutig auf den Geschäftsregeln*. Was den Anwendungsdienst betrifft, ist es genau das, was du beschreibst, die meiste Zeit beginne ich damit, diesen Geschäftsablauf in meine Controlleraktionen zu setzen, und wenn ich es bemerke, refaktoriere ich diese Logik in der Anwendungsdienstschicht. Man könnte sagen, dass diese Schicht für Anwendungsfälle ist.

1 Stimmen

*Und solche Domänen-Service-Schnittstellen werden von den Domänen-Entitäten genutzt.

1 Stimmen

Der Blog-Post-Link ist defekt. Kann jemand einen funktionierenden finden?

66voto

Timo Punkte 6828

Im Roten Buch (Implementierung von Domain-Driven Design von Vaughn Vernon) ist dies, wie ich die Konzepte verstehe:

Domänenobjekte (Entitäten und Wertobjekte) umfassen das Verhalten, das von der (Teil-) Domäne benötigt wird, wodurch es natürlich, ausdrucksstark und verständlich wird.

Domänendienste umfassen solche Verhaltensweisen, die nicht in ein einzelnens Domänenobjekt passen. Zum Beispiel könnte eine Buchbibliothek einem Klienten ein Buch ausleihen (mit entsprechenden Bestands-Änderungen) dies könnte von einem Domänendienst durchgeführt werden.

Anwendungsdienste steuern den Ablauf von Anwendungsfällen, einschließlich aller zusätzlichen Anforderungen, die über die Domäne hinaus benötigt werden. Oft stellt es solche Methoden über seine API zur Verfügung, die von externen Clients genutzt werden können. Um auf unser vorheriges Beispiel aufzubauen, könnte unser Anwendungsdienst eine Methode BuchAnKlientenAusleihen(Guid buchGuid, Guid klientGuid) bereitstellen, die:

  • Ruft den Klienten ab.
  • Bestätigt seine Berechtigungen. (Beachten Sie, wie wir unser Domänenmodell frei von Sicherheits- / Benutzerverwaltungsproblemen gehalten haben. Eine solche Verunreinigung könnte zu vielen Problemen führen. Stattdessen erfüllen wir diese technische Anforderung hier, in unserem Anwendungsdienst.)
  • Ruft das Buch ab.
  • Ruft den Domänendienst auf (übermittelt den Klient und das Buch), um die tatsächliche Domänenlogik des Ausleihens des Buches an den Klienten zu behandeln. Ich stelle mir vor, dass die Bestätigung der Verfügbarkeit des Buches definitiv Teil der Domänenlogik ist.

Ein Anwendungsdienst sollte im Allgemeinen einen sehr einfachen Ablauf haben. Komplexe Anwendungsdienstabläufe deuten häufig darauf hin, dass die Domänenlogik aus der Domäne ausgetreten ist.

Wie Sie hoffentlich sehen können, bleibt das Domänenmodell so sehr sauber und ist leicht zu verstehen und mit den Domänenexperten zu besprechen, da es nur eigene, tatsächliche geschäftliche Anliegen enthält. Der Anwendungsablauf hingegen ist auch viel einfacher zu verwalten, da er von Domänenanliegen befreit ist und prägnant und unkompliziert wird.

3 Stimmen

Ich würde sagen, dass der Anwendungsdienst auch der Punkt ist, an dem Abhängigkeiten aufgelöst werden. Seine Methode ist ein Anwendungsfall, ein einzelner Ablauf, um informierte Entscheidungen über konkrete Implementierungen zu treffen. Datenbanktransaktionen passen hier auch gut rein.

2 Stimmen

Persönlich finde ich, dass "Berechtigungen" oft mehr ein Bereichsthema sind, als die Leute denken. Zum Beispiel klingt "Bücher nur an Kunden in gutem Ruf ausleihen" für mich nach einer Geschäftsregel. Natürlich benötigen Sie möglicherweise einige Anwendungslogik, um Dinge wie Rohberechtigungen in den Bereichsstatus "guter Ruf" einer Client-Entität zu übersetzen.

0 Stimmen

@Timo Wie kann man sicherstellen/erzwingen, dass wir einen Domain-Service für einen bestimmten Anwendungsfall verwenden?

50voto

kboom Punkte 2079

Dienst für Domäne ist die Erweiterung der Domäne. Es sollte nur im Kontext der Domäne gesehen werden. Das ist keine Benutzeraktion wie zum Beispiel Konto schließen oder so etwas. Der Domänendienst passt dort, wo kein Zustand vorhanden ist. Ansonsten wäre es ein Domänenobjekt. Der Domänendienst tut etwas, das nur dann sinnvoll ist, wenn es mit anderen Mitarbeitern (Domänenobjekten oder anderen Diensten) erledigt wird. Und dieses Sinn machen ist die Verantwortung einer anderen Schicht.

Anwendungsdienst ist jene Schicht, die die Initialisierung und Überwachung der Interaktion zwischen den Domänenobjekten und -diensten durchführt. Der Ablauf ist im Allgemeinen wie folgt: Domänenobjekt (oder Objekte) aus dem Repository abrufen, eine Aktion ausführen und es (sie) wieder dort platzieren (oder auch nicht). Es kann mehr tun – zum Beispiel überprüfen, ob ein Domänenobjekt existiert oder nicht, und entsprechend Ausnahmen werfen. Es ermöglicht also dem Benutzer, mit der Anwendung zu interagieren (und hieraus stammt wahrscheinlich sein Name) – durch die Manipulation von Domänenobjekten und -diensten. Anwendungsdienste sollten im Allgemeinen alle möglichen Anwendungsfälle repräsentieren. Wahrscheinlich das Beste, was Sie tun können, bevor Sie über die Domäne nachdenken, ist die Erstellung von Anwendungsdienstschnittstellen, die Ihnen einen viel besseren Einblick in das geben, was Sie wirklich versuchen zu tun. Mit diesem Wissen können Sie sich auf die Domäne konzentrieren.

Repositories können im Allgemeinen in Domänendienste injiziert werden, aber dies ist eher ein seltener Fall. Meistens ist es jedoch die Anwendungsschicht, die dies tut.

20 Stimmen

"Der Domänendienst passt dorthin, wo es keinen Zustand gibt. Ansonsten wäre es ein Domänenobjekt." hat es für mich klick gemacht. Danke.

0 Stimmen

@Nick kannst du es erklären?

0 Stimmen

Eines der besten Dinge, die ich über diese schwierige Unterscheidung gelesen habe. Danke.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X