Obecnie studiuję DDD i mam pytania dotyczące zarządzania repozytoriami za pomocą DDD.
Właściwie spotkałem dwie możliwości:
Pierwszy
Pierwszym sposobem zarządzania usługami, które przeczytałem, jest wstrzyknięcie repozytorium i modelu domeny do usługi aplikacji.
W ten sposób, w jednej z metod usługi aplikacji, wywołujemy metodę usługi domeny (sprawdzanie reguł biznesowych), a jeśli warunek jest dobry, repozytorium jest wywoływane specjalną metodą w celu utrwalenia / odzyskania jednostki z bazy danych.
Prostym sposobem na zrobienie tego może być:
class ApplicationService{
constructor(domainService, repository){
this.domainService = domainService
this.repository = repository
}
postAction(data){
if(this.domainService.validateRules(data)){
this.repository.persist(new Entity(data.name, data.surname))
}
// ...
}
}
Drugi
Drugą możliwością jest wstrzyknięcie repozytorium do wnętrza usługi domainService i korzystanie z repozytorium tylko za pośrednictwem usługi domeny:
class ApplicationService{
constructor(domainService){
this.domainService = domainService
}
postAction(data){
if(this.domainService.persist(data)){
console.log('all is good')
}
// ...
}
}
class DomainService{
constructor(repository){
this.repository = repository
}
persist(data){
if(this.validateRules(data)){
this.repository.save(new Entity(data.name))
}
}
validateRules(data){
// returns a rule matching
}
}
Odtąd nie jestem w stanie rozróżnić, który jest najlepszy (jeśli jest najlepszy) lub co im to sugeruje w swoim kontekście.
Czy możesz podać mi przykład, gdzie jedno może być lepsze od drugiego i dlaczego?
źródło
Odpowiedzi:
Krótka odpowiedź brzmi - możesz używać repozytoriów z usługi aplikacji lub usługi domeny - ale ważne jest, aby zastanowić się, dlaczego i jak to robisz.
Cel usługi domenowej
Usługi domenowe powinny zawierać koncepcje / logikę domeny - jako taką, metoda usługi domenowej:
nie należy do usługi domenowej, ponieważ
persist
nie jest częścią wszechobecnego języka, a operacja trwałości nie jest częścią logiki biznesowej domeny.Zasadniczo usługi domenowe są przydatne, gdy masz reguły / logikę biznesową, które wymagają koordynacji lub pracy z więcej niż jednym agregatem. Jeśli logika dotyczy tylko jednego agregatu, powinna być w metodzie na jednostkach tego agregatu.
Repozytoria w usługach aplikacyjnych
W tym sensie, w twoim przykładzie, wolę twoją pierwszą opcję - ale nawet tam jest miejsce na ulepszenia, ponieważ twoja usługa domeny przyjmuje surowe dane z interfejsu API - dlaczego usługa domeny powinna wiedzieć o strukturze
data
? Ponadto wydaje się, że dane są powiązane tylko z pojedynczym agregatem, więc korzystanie z usługi domenowej jest ograniczone - generalnie umieszczam walidację w konstruktorze encji. na przykładi wrzuć wyjątek, jeśli jest nieważny. W zależności od frameworka aplikacji, może być łatwo mieć spójny mechanizm wychwytywania wyjątku i mapowania go na odpowiednią odpowiedź dla typu interfejsu API - np. Dla interfejsu API REST, zwróć kod statusu 400.
Repozytoria w usługach domenowych
Niezależnie od powyższego, czasami przydatne jest wstrzykiwanie i używanie repozytorium w usłudze domenowej, ale tylko wtedy, gdy repozytoria są zaimplementowane w taki sposób, że akceptują i zwracają tylko zagregowane katalogi główne, a także tam, gdzie abstrakcyjna jest logika obejmująca wiele agregatów. na przykład
implementacja usługi domeny wyglądałaby następująco:
Wniosek
Kluczem jest tutaj to, że usługa domeny zawiera w sobie proces, który jest częścią wszechobecnego języka. Aby wypełnić swoją rolę, musi korzystać z repozytoriów - i jest to całkowicie w porządku.
Ale dodanie usługi domeny, która otacza repozytorium metodą zwaną, nie
persist
ma żadnej wartości.Na tej podstawie, jeśli usługa aplikacji wyraża przypadek użycia, który wymaga tylko pracy z jednym agregatem, nie ma problemu z użyciem repozytorium bezpośrednio z usługi aplikacji.
źródło
Wystąpił problem z zaakceptowaną odpowiedzią:
Model domeny nie może zależeć od repozytorium, a usługa domeny jest częścią modelu domeny -> usługa domeny nie powinna zależeć od repozytorium.
Zamiast tego należy zgromadzić wszystkie jednostki, które są potrzebne do wykonania logiki biznesowej już w usłudze aplikacji, a następnie po prostu dostarczyć swoim modelom obiekty instancji.
W oparciu o twój przykład może to wyglądać następująco:
Ogólna zasada: model domeny nie zależy od zewnętrznych warstw
Aplikacja a usługa domenowa Z tego artykułu :
Usługi domenowe są bardzo szczegółowe, ponieważ jako usługi aplikacyjne mają na celu zapewnienie interfejsu API.
Usługi domenowe zawierają logikę domeny, której naturalnie nie można umieścić w encji lub obiekcie wartości, podczas gdy usługi aplikacji sterują wykonywaniem logiki domeny i same nie implementują żadnej logiki domeny.
Metody usług domenowych mogą mieć inne elementy domeny, takie jak argumenty i zwracane wartości, podczas gdy usługi aplikacji działają na prostych argumentach, takich jak wartości tożsamości i prymitywne struktury danych.
Usługi aplikacji deklarują zależności od usług infrastrukturalnych wymaganych do wykonania logiki domeny.
źródło
Żaden z twoich wzorców nie jest dobry, chyba że twoje usługi i przedmioty zawierają pewien spójny zestaw odpowiedzialności.
Najpierw powiedz, jaki jest Twój obiekt domeny i porozmawiaj o tym, co może zrobić w języku domeny. Jeśli może być poprawne lub niepoprawne, dlaczego nie mieć tego jako właściwości samego obiektu domeny?
Jeśli na przykład ważność obiektów ma sens tylko w odniesieniu do innego obiektu, być może masz odpowiedzialność za „regułę sprawdzania poprawności X dla obiektów domeny”, która może być zawarta w zestawie usług.
Czy sprawdzanie poprawności obiektu wymaga przechowywania go w ramach reguł biznesowych? Prawdopodobnie nie. Odpowiedzialność za „przechowywanie obiektów” zwykle spoczywa w oddzielnym obiekcie repozytorium.
Teraz masz operację, którą chcesz wykonać, która obejmuje zakres obowiązków, stwórz obiekt, zweryfikuj go i jeśli jest ważny, zapisz go.
Czy ta operacja jest nieodłączna od obiektu domeny? Następnie uczyń go częścią tego obiektu, tj
ExamQuestion.Answer(string answer)
Czy pasuje do innej części Twojej domeny? połóż to tam
Basket.Purchase(Order order)
Wolisz robić usługi ADM REST? Ok, więc.
źródło