it-swarm.com.de

Domänengesteuertes Design: Domänendienst, Anwendungsdienst

Kann jemand den Unterschied zwischen Domain- und Anwendungsdiensten anhand einiger Beispiele erläutern? Und wenn es sich bei einem Dienst um einen Domänendienst handelt, würde ich die tatsächliche Implementierung dieses Dienstes in die Domänenassembly einfügen, und wenn ja, würde ich auch Repositorys in diesen Domänendienst einfügen? Einige Infos wären wirklich hilfreich.

236
Chris

Dienste gibt es in drei Varianten: Domänendienste, Anwendungsdienste und Infrastrukturservices.

  • Domain Services: Verkapselt Geschäftslogik , die nicht in ein Domain-Objekt passt und NICHT typische CRUD-Operationen - diese gehören zu einem Repository .
  • Application Services: Wird von externen Verbrauchern verwendet, um mit Ihrem System zu kommunizieren (think Web Services ). Wenn Verbraucher Zugang zu CRUD-Operationen benötigen, sind sie hier exponiert.
  • Infrastructure Services: Dient zum Abstrahieren technischer Probleme (z. B. MSMQ, E-Mail-Anbieter usw.).

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

Application Services verwendet in der Regel sowohl Domain Services-Repositorys als auch , um externe Anforderungen zu bearbeiten.

Hoffentlich hilft das!

314
Vijay Patel

(Wenn Sie keine Lust zum Lesen haben, finden Sie unten eine Zusammenfassung :-)

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

Andere Ressourcen

Es gibt nur sehr wenige Informationen zu Anwendungsdiensten. Themen wie aggregierte Roots, Repositorys und Domänendienste werden ausführlich behandelt, Anwendungsdienste werden jedoch nur kurz erwähnt oder ganz weggelassen.

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

Jeffrey Palermo Artikel über die Zwiebel-Architektur (Teil eins , zwei und drei ) sind eine gute Lektüre. Er behandelt Anwendungsdienste als Konzepte auf Anwendungsebene , z. B. als Benutzersitzung. Dies entspricht zwar eher meinem Verständnis von Anwendungsdiensten, entspricht aber immer noch nicht meinen Überlegungen zu diesem Thema.

Meine Gedanken

Ich stelle mir Anwendungsdienste als Abhängigkeiten vor, die von der Anwendung bereitgestellt werden . In diesem Fall kann die Anwendung eine Desktop-Anwendung oder ein WCF-Dienst sein.

Domain

Zeit für ein Beispiel. Sie beginnen mit Ihrer Domain. Hier werden alle Entitäten und Domänendienste implementiert, die nicht von externen Ressourcen abhängig sind. Alle Domänenkonzepte, die von externen Ressourcen abhängen, werden von einer Schnittstelle definiert. Hier ist ein mögliches Lösungslayout (Projektname in Fettdruck):

Meine Lösung
- Mein.Produkt.Kern (My.Product.dll) 
 - DomainServices 
 IExchangeRateService 
 Product 
 ProductFactory 
 IProductRepository 

Die Klassen Product und ProductFactory wurden in der Core Assembly implementiert. Das IProductRepository wird wahrscheinlich von einer Datenbank gesichert. Die Implementierung ist nicht das Anliegen der Domain und wird daher durch eine Schnittstelle definiert.

Im Moment konzentrieren wir uns auf IExchangeRateService. Die Geschäftslogik für diesen Service wird von einem externen Webservice implementiert. Sein Konzept ist jedoch immer noch Teil der Domäne und wird durch diese Schnittstelle dargestellt.

Infrastruktur

Die Implementierung der externen Abhängigkeiten ist Teil der Infrastruktur der Anwendung:

 Meine Lösung 
 + Mein.Produkt.Kern (My.Product.dll) 
 - Meine.Produkt.Infrastruktur (My.Product.Infrastructure.dll) 
 - DomainServices 
 XEExchangeRateService 
 SqlServerProductRepository 

XEExchangeRateService implementiert den Domänendienst IExchangeRateService durch Kommunikation mit xe.com . Diese Implementierung kann von Ihren Anwendungen verwendet werden, die Ihr Domänenmodell verwenden, indem die Infrastrukturassembly eingeschlossen wird.

Anwendung

Beachten Sie, dass ich Anwendungsdienste noch nicht erwähnt habe. Wir werden uns diese jetzt ansehen. Angenommen, wir möchten eine IExchangeRateService -Implementierung bereitstellen, die einen Cache für schnelle Suchvorgänge verwendet. Der Umriss dieser Dekorationsklasse könnte so aussehen.

public class CachingExchangeRateService : IExchangeRateService
{
    private IExchangeRateService service;
    private ICache cache;

    public CachingExchangeRateService(IExchangeRateService service, ICache cache)
    {
        this.service = service;
        this.cache = cache;
    }

    // Implementation that utilizes the provided service and cache.
}

Beachten Sie den Parameter ICache? Dieses Konzept ist nicht Teil unserer Domain, daher handelt es sich nicht um einen Domain-Service. Es ist ein Anwendungsdienst . Dies ist eine Abhängigkeit von unserer Infrastruktur, die möglicherweise von der Anwendung bereitgestellt wird. Lassen Sie uns eine Anwendung vorstellen, die dies demonstriert:

Meine Lösung
- Mein.Produkt.Kern (My.Product.dll) 
 - DomainServices 
 IExchangeRateService 
 Product 
 ProductFactory 
 IProductRepository 
 - Meine.Produkt.Infrastruktur (My.Product.Infrastructure.dll) 
 - ApplicationServices 
 ICache 
 - DomainServices 
 CachingExchangeRateService 
 XEExchangeRateService 
 SqlServerProductRepository 
 - Mein.Produkt.WcfService (My.Product.WcfService.dll) 
 - ApplicationServices 
 MemcachedCache 
 IMyWcfService.cs 
 + MyWcfService.svc 
 + Web.config 

Dies alles läuft in der Anwendung folgendermaßen ab:

// Set up all the dependencies and register them in the IoC container.
var service = new XEExchangeRateService();
var cache = new MemcachedCache();
var cachingService = new CachingExchangeRateService(service, cache);

ServiceLocator.For<IExchangeRateService>().Use(cachingService);

Zusammenfassung

Eine vollständige Anwendung besteht aus drei Hauptschichten:

  • domain
  • infrastruktur
  • anwendung

Die Domänenschicht enthält die Domänenentitäten und eigenständigen Domänendienste. Jede Domäne Konzepte (dies schließt Domänendienste, aber auch Repositorys ein), die von externen Ressourcen abhängt, wird durch Schnittstellen definiert.

Die Infrastrukturschicht enthält die Implementierung der Schnittstellen aus der Domänenschicht. Diese Implementierungen können neue non-domain Abhängigkeiten einführen, die der Anwendung bereitgestellt werden müssen. Dies sind die Anwendungsdienste und werden durch Schnittstellen dargestellt.

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

Obwohl diese Perspektive möglicherweise nicht mit der allgemeinen DDD-Definition von Diensten übereinstimmt, wird die Domäne von der Anwendung getrennt und Sie können die Domänen- (und Infrastruktur-) Assembly für mehrere Anwendungen freigeben.

106

Die beste Ressource, die mir geholfen hat, den Unterschied zwischen einem Anwendungsdienst und einem Domänendienst zu verstehen, war die Java Implementierung des Frachtbeispiels von Eric Evans, gefunden hier In diesem Fall können Sie die Interna von RoutingService (ein Domänendienst) und BookingService, CargoInspectionService (Anwendungsdienste) überprüfen.

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

  • Lesen Sie die Beschreibung der Dienste im obigen Link, genauer gesagt diesen Satz:

Domänendienste werden in Form der allgegenwärtigen Sprache und der Domänentypen ausgedrückt, d. H. Die Methodenargumente und die Rückgabewerte sind geeignete Domänenklassen.

  • Lesen Sie diese Blog-Post , vor allem diesen Teil:

Was ich beim Trennen der Äpfel von den Orangen als große Hilfe empfinde, ist das Denken in Bezug auf den Anwendungsworkflow. Alle Logik in Bezug auf den Anwendungsworkflow wird in der Regel in Application Services in die Anwendungsschicht einbezogen, wohingegen Konzepte aus der Domäne, die offenbar nicht als Modellobjekte passen, einen oder mehrere Domain Services bilden.

35
Ghola

Aus dem Roten Buch (Implementing Domain Driven Design, von Vaughn Vernon) verstehe ich die Konzepte wie folgt:

Domänenobjekte (Entitäten und Wertobjekte) kapseln das von der (Sub-) Domäne geforderte Verhalten und machen es natürlich, ausdrucksstark und verständlich.

Domänendienste kapselt solche Verhaltensweisen, die nicht in ein einzelnes Domänenobjekt passen. Beispielsweise könnte eine Buchbibliothek, die ein Book an ein Client ausleiht (mit entsprechenden Inventory Änderungen), dies von einem Domänendienst aus tun.

Anwendungsdienste behandeln den Fluss von Anwendungsfällen, einschließlich aller zusätzlichen Bedenken, die zusätzlich zu den der Domäne erforderlich sind. Solche Methoden werden häufig über die API für den Verbrauch durch externe Clients verfügbar gemacht. Um auf unserem vorherigen Beispiel aufzubauen, könnte unser Anwendungsservice eine Methode LendBookToClient(Guid bookGuid, Guid clientGuid) verfügbar machen, die:

  • Ruft das Client ab.
  • Bestätigt seine Berechtigungen. ( Beachten Sie, wie wir unser Domain-Modell frei von Sicherheits-/Benutzerverwaltungsproblemen gehalten haben. Diese Verschmutzung kann zu vielen Problemen führen. Stattdessen erfüllen wir diese technische Anforderung hier in unserem Anwendungsservice. )
  • Ruft das Book ab.
  • Ruft den Domänendienst auf (der Client und Book übergibt), um die tatsächliche Domänenlogik für das Ausleihen des Buches zu verarbeiten der Kunde. Ich stelle mir zum Beispiel 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 weisen häufig darauf hin, dass die Domänenlogik aus der Domäne ausgelaufen ist.

Wie Sie hoffentlich sehen können, bleibt das Domain-Modell auf diese Weise sehr sauber und ist leicht zu verstehen und mit der Domain zu diskutieren Experten, weil es nur seine eigenen, tatsächlichen Geschäftsinteressen enthält. Der Anwendungsfluss ist andererseits auch viel einfacher zu verwalten, da er von Domain-Bedenken befreit ist, und wird kurz und unkompliziert.

27
Timo

Domain Service ist die Erweiterung der Domain. Es sollte nur im Kontext der Domain gesehen werden. Dies ist keine Benutzeraktion wie zum Beispiel Konto schließen oder so. Der Domain-Service passt dort hin, wo es keinen Status gibt. Andernfalls wäre es ein Domain-Objekt. Der Domänendienst macht nur Sinn, wenn er mit anderen Mitarbeitern (Domänenobjekten oder anderen Diensten) ausgeführt wird. Und dass Sinn ergibt , liegt in der Verantwortung einer anderen Ebene.

Anwendungsdienst ist die Ebene, die die Interaktion zwischen den Domänenobjekten und -diensten initialisiert und überwacht. Der Ablauf sieht im Allgemeinen so aus: Holen Sie sich ein Domain-Objekt (oder Objekte) aus dem Repository, führen Sie eine Aktion aus und platzieren Sie es (sie) wieder dort (oder nicht). Es kann mehr tun - zum Beispiel kann es prüfen, ob ein Domain-Objekt existiert oder nicht und Ausnahmen entsprechend auslösen. Auf diese Weise kann der Benutzer mit der Anwendung interagieren (und hierher stammt wahrscheinlich auch der Name), indem er Domänenobjekte und -dienste manipuliert. Anwendungsdienste sollten im Allgemeinen alle möglichen Anwendungsfälle darstellen . Wahrscheinlich ist es das Beste, was Sie tun können, bevor Sie über die Domäne nachdenken, Anwendungsdienst-Schnittstellen zu erstellen, die Ihnen einen viel besseren Einblick in das geben, was Sie wirklich versuchen. Mit diesem Wissen können Sie sich auf die Domäne konzentrieren.

Repositorys können im Allgemeinen in Domänendienste eingefügt werden, dies ist jedoch ein eher seltenes Szenario. Es ist jedoch die Anwendungsebene, die dies die meiste Zeit tut.

24
kboom

Domain Services: Methoden, die nicht wirklich auf eine einzelne Entität passen oder Zugriff auf das Repository erfordern, sind in Domain Services enthalten. Die Domain-Service-Schicht kann auch eine eigene Domain-Logik enthalten und ist ebenso Teil des Domain-Modells wie Entitäten und Wertobjekte.

Application Services: Der Application Service ist eine dünne Schicht, die sich über dem Domain-Modell befindet und die Anwendungsaktivität koordiniert. Es enthält keine Geschäftslogik und enthält keinen Status von Entitäten. Es kann jedoch den Status einer geschäftlichen Workflow-Transaktion speichern. Mithilfe eines Anwendungsdienstes stellen Sie dem Domänenmodell eine API mit dem Messaging-Muster "Request-Reply" zur Verfügung.

Millett, C (2010). Professionelle ASP.NET-Entwurfsmuster. Wiley Publishing. 92.

8
GorkemHalulu

Domänendienste : Ein Dienst, der eine Geschäftslogik ausdrückt, die nicht Teil eines aggregierten Stamms ist.

  • Sie haben 2 Aggregate:

    • Product der Name und Preis enthält.
    • Purchase enthält das Kaufdatum, die Liste der bestellten Produkte mit der Menge und dem Produktpreis zu diesem Zeitpunkt sowie die Zahlungsmethode.
  • Checkout ist nicht Teil eines dieser beiden Modelle und gehört zu Ihrem Geschäftsmodell.

  • Checkout kann als Domain-Service erstellt werden, der das gesamte Produkt abruft und den Gesamtpreis berechnet, den Gesamtbetrag durch Aufrufen eines anderen Domain-Service PaymentService mit einem Implementierungsteil von Infrastructure bezahlt und in konvertiert Purchase.

Anwendungsdienste : Ein Dienst, der "orchestriert" oder Domänenmethoden ausübt. Dies kann so einfach sein wie nur Ihr Controller.

Dies ist der Ort, an dem Sie normalerweise Folgendes tun:

public String createProduct(...some attributes) {
  if (productRepo.getByName(name) != null) {
    throw new Exception();
  }

  productId = productRepository.nextIdentity();

  product = new Product(productId, ...some attributes);

  productRepository.save(product);

  return productId.value();
  // or Product itself
  // or just void if you dont care about result
}

public void renameProduct(productId, newName) {
  product = productRepo.getById(productId);

  product.rename(newName);

  productRepo.save(product);
}

Sie können hier beispielsweise überprüfen, ob ein Product eindeutig ist. Sofern ein Product nicht eindeutig ist, sollte dies Teil des Domänendienstes sein, der möglicherweise UniqueProductChecker heißt, da er nicht Teil der Klasse Product und sein kann Es interagiert mit mehreren Aggregaten.

Hier ist ein vollständiges Beispiel für ein DDD-Projekt: https://github.com/VaughnVernon/IDDD_Samples

Sie finden viele Beispiele für Anwendungsdienste und einige für Domänendienste

2
doesnotmatter