답변:
서비스는 도메인 서비스 , 응용 프로그램 서비스 및 인프라 서비스의 세 가지 형태로 제공 됩니다.
도메인 서비스와 함께 도메인 서비스를 유지하는 것은 합리적입니다. 모두 도메인 논리에 중점을 둡니다. 예, 리포지토리를 서비스에 주입 할 수 있습니다.
응용 프로그램 서비스는 일반적으로 도메인 서비스 와 리포지토리를 모두 사용 하여 외부 요청을 처리합니다.
희망이 도움이됩니다!
(읽고 싶지 않다면 하단에 요약이 있습니다 :-)
나도 응용 프로그램 서비스의 정확한 정의로 어려움을 겪었습니다. Vijay의 답변은 한 달 전에 내 사고 과정에 매우 도움이되었지만 그 일부에 동의하지 않았습니다.
응용 프로그램 서비스에 대한 정보는 거의 없습니다. 집계 루트, 저장소 및 도메인 서비스와 같은 주제는 광범위하게 논의되지만 애플리케이션 서비스는 간략하게 언급되거나 완전히 생략됩니다.
MSDN Magazine 기사 도메인 기반 디자인 소개 에서는 도메인 모델을 외부 클라이언트 (예 : WCF 서비스)로 변환 및 / 또는 노출하는 방법으로 응용 프로그램 서비스를 설명합니다. 이것이 Vijay가 애플리케이션 서비스를 설명하는 방식입니다. 이러한 관점에서 응용 프로그램 서비스는 도메인에 대한 인터페이스 입니다.
Onion Architecture에 관한 Jeffrey Palermo의 기사 ( 1 부 , 2 부 및 3 부 )는 잘 읽습니다. 그는 응용 프로그램 서비스를 사용자 세션과 같은 응용 프로그램 레벨 개념 으로 취급합니다 . 이것은 응용 프로그램 서비스에 대한 이해에 더 가깝지만 여전히 주제에 대한 나의 생각과 일치하지 않습니다.
응용 프로그램 서비스가 응용 프로그램에서 제공하는 종속성 으로 생각하게되었습니다 . 이 경우 응용 프로그램은 데스크톱 응용 프로그램 또는 WCF 서비스 일 수 있습니다.
예를 들어 시간입니다. 당신은 당신의 도메인으로 시작합니다. 외부 자원에 의존하지 않는 모든 엔티티 및 도메인 서비스가 여기에 구현됩니다. 외부 자원에 의존하는 모든 도메인 개념은 인터페이스에 의해 정의됩니다. 가능한 솔루션 레이아웃은 다음과 같습니다 (프로젝트 이름은 굵게 표시됨).
내 솔루션 - My.Product.Core (My.Product.dll) -도메인 서비스 IExchangeRateService 생성물 제품 공장 IProductRepository
Product
및 ProductFactory
클래스는 코어 어셈블리에 구현되었다. 는 IProductRepository
아마 데이터베이스에 의해 백업됩니다 무언가이다. 이것의 구현은 도메인의 관심사가 아니므로 인터페이스에 의해 정의됩니다.
지금은에 초점을 맞출 것 IExchangeRateService
입니다. 이 서비스의 비즈니스 로직은 외부 웹 서비스에 의해 구현됩니다. 그러나이 개념은 여전히 도메인의 일부이며이 인터페이스로 표시됩니다.
외부 종속성의 구현은 응용 프로그램 인프라의 일부입니다.
내 솔루션 + My.Product.Core (My.Product.dll) - My.Product.Infrastructure (My.Product.Infrastructure.dll) -도메인 서비스 XEExchangeRateService SqlServerProductRepository
XEExchangeRateService
xe.comIExchangeRateService
과 통신 하여 도메인 서비스를 구현합니다 . 이 구현은 인프라 어셈블리를 포함하여 도메인 모델을 사용하는 응용 프로그램에서 사용할 수 있습니다.
아직 애플리케이션 서비스에 대해서는 언급하지 않았습니다. 우리는 지금 그것들을 볼 것입니다. IExchangeRateService
빠른 조회를 위해 캐시를 사용 하는 구현 을 제공한다고 가정 해 보겠습니다 . 이 데코레이터 클래스의 개요는 다음과 같습니다.
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.
}
통지 ICache
매개 변수를? 이 개념은 도메인의 일부가 아니므로 도메인 서비스가 아닙니다. 그것은이다 애플리케이션 서비스 . 애플리케이션에서 제공 할 수있는 인프라의 종속성입니다. 이것을 보여주는 응용 프로그램을 소개합시다 :
내 솔루션 - My.Product.Core (My.Product.dll) -도메인 서비스 IExchangeRateService 생성물 제품 공장 IProductRepository - My.Product.Infrastructure (My.Product.Infrastructure.dll) -응용 서비스 ICache -도메인 서비스 CachingExchangeRateService XEExchangeRateService SqlServerProductRepository - My.Product.WcfService (My.Product.WcfService.dll) -응용 서비스 MemcachedCache IMyWcfService.cs + MyWcfService.svc + Web.config
이것은 모두 다음과 같이 응용 프로그램에서 함께 제공됩니다.
// 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);
완전한 응용 프로그램은 세 가지 주요 계층으로 구성됩니다.
도메인 계층에는 도메인 엔티티 및 독립형 도메인 서비스가 포함됩니다. 외부 리소스에 의존하는 모든 도메인 개념 (도메인 서비스 및 리포지토리 포함)은 인터페이스로 정의됩니다.
인프라 계층에는 도메인 계층의 인터페이스 구현이 포함됩니다. 이러한 구현은 애플리케이션에 제공되어야하는 새로운 비 도메인 종속성을 도입 할 수 있습니다. 이들은 응용 프로그램 서비스이며 인터페이스로 표시됩니다.
응용 프로그램 계층에는 응용 프로그램 서비스의 구현이 포함됩니다. 인프라 스트럭처 계층에서 제공하는 구현이 충분하지 않은 경우 응용 프로그램 계층에는 도메인 인터페이스의 추가 구현도 포함될 수 있습니다.
이 관점은 일반적인 DDD 서비스 정의와 일치하지 않을 수 있지만 도메인을 응용 프로그램과 분리하고 여러 응용 프로그램간에 도메인 (및 인프라) 어셈블리를 공유 할 수 있습니다.
IExchangeRateService
인터페이스 를 의미 합니까? 이것은 도메인 개념, 즉 고객의 유비쿼터스 언어에 포함 된 개념입니다. 도메인의 다른 부분이이 서비스에 의존 할 수 있으므로 해당 인터페이스가 도메인 계층에 정의되어 있습니다. 그러나 구현에는 외부 웹 서비스가 포함되므로 구현 클래스는 인프라 계층에 있습니다. 이런 식으로 도메인 계층은 비즈니스 로직에만 관련됩니다.
ExchangeRate
기본 통화, 카운터 통화 및이 두 통화 간의 환율 값을 포함 하는 인스턴스 일 수 있습니다 . 이와 밀접하게 관련된 값은 도메인의 '교환 율'개념을 나타내므로 도메인 계층에 있습니다. 간단한 DTO처럼 보이지만 DDD에서는 값 개체라고하며 인스턴스를 비교하거나 변환하기위한 추가 비즈니스 논리를 포함 할 수 있습니다.
애플리케이션 서비스와 도메인 서비스의 차이점을 이해하는 데 도움이 된 최고의 리소스는 here 에있는 Eric Evans의화물 예제의 Java 구현이었습니다 . 로드하지 않으면 RoutingService (도메인 서비스)와 BookingService CargoInspectionService (응용 프로그램 서비스)의 내부를 확인할 수 있습니다.
내 'aha'순간은 두 가지로 인해 유발되었습니다.
위의 링크에서 서비스에 대한 설명, 더 정확하게는이 문장을 읽으십시오.
도메인 서비스는 유비쿼터스 언어와 도메인 유형으로 표현됩니다. 즉, 메소드 인수와 반환 값은 적절한 도메인 클래스입니다.
이 블로그 게시물 , 특히이 부분을 읽으십시오 .
사과를 오렌지에서 분리하는 데 큰 도움이되는 것은 응용 프로그램 워크 플로우 측면에서 생각하는 것입니다. 응용 프로그램 워크 플로와 관련된 모든 논리는 일반적으로 응용 프로그램 서비스 계층에 응용 프로그램 서비스를 고려한 반면 모델 개체에 맞지 않는 도메인의 개념은 결국 하나 이상의 도메인 서비스를 형성합니다.
도메인 서비스 는 도메인 의 확장입니다. 도메인 컨텍스트에서만 볼 수 있습니다. 예를 들어 계정 해지와 같은 사용자 작업이 아닙니다 . 도메인 서비스는 상태가없는 곳에 적합합니다. 그렇지 않으면 도메인 개체가됩니다. 도메인 서비스는 다른 공동 작업자 (도메인 개체 또는 다른 서비스)와 함께 작업 할 때만 의미가있는 작업을 수행합니다. 그리고 그 이해 는 다른 계층의 책임입니다.
응용 프로그램 서비스 는 도메인 개체와 서비스 간의 상호 작용을 초기화하고 감독하는 계층입니다. 플로우는 일반적으로 저장소에서 도메인 오브젝트를 가져 와서 조치를 실행 한 후 다시 배치합니다. 더 많은 작업을 수행 할 수 있습니다. 예를 들어 도메인 개체의 존재 여부를 확인하고 그에 따라 예외를 throw 할 수 있습니다. 따라서 사용자는 도메인 개체와 서비스를 조작하여 응용 프로그램과 상호 작용할 수 있습니다 (그리고 이름이 유래 한 곳일 수도 있음). 응용 프로그램 서비스는 일반적으로 가능한 모든 사용 사례를 나타내야합니다.. 아마도 도메인에 대해 생각하기 전에 할 수있는 최선의 방법은 응용 프로그램 서비스 인터페이스를 작성하여 실제로 수행하려는 작업에 대한 더 나은 통찰력을 제공하는 것입니다. 그러한 지식이 있으면 도메인에 집중할 수 있습니다.
리포지토리는 일반적으로 도메인 서비스에 주입 될 수 있지만 이는 드문 시나리오입니다. 그래도 대부분의 시간을하는 것은 응용 프로그램 계층입니다.
레드 북 (Vaughn Vernon의 도메인 기반 디자인 구현)에서이 개념을 이해합니다.
도메인 객체 ( 엔티티 및 값 객체 )는 (하위) 도메인에 필요한 동작을 캡슐화하여 자연스럽고 표현 가능하며 이해하기 쉽게 만듭니다.
도메인 서비스 는 단일 도메인 개체에 맞지 않는 이러한 동작을 캡슐화 합니다. 예를 들어, a에 a Book
를 대출하는 서적 라이브러리 Client
(해당 Inventory
변경 사항 포함)는 도메인 서비스에서 수행 할 수 있습니다.
응용 프로그램 서비스 는 도메인 에 필요한 추가 문제를 비롯하여 사용 사례 흐름을 처리합니다 . 종종 외부 클라이언트가 사용할 수 있도록 API를 통해 이러한 메소드를 노출합니다. 이전 예제를 바탕으로 애플리케이션 서비스는 다음과 같은 메소드 LendBookToClient(Guid bookGuid, Guid clientGuid)
를 노출 할 수 있습니다 .
Client
.Book
.Client
및 전달 Book
) 하여 클라이언트에게 책을 대출하는 실제 도메인 논리 를 처리합니다 . 예를 들어 책의 가용성을 확인하는 것이 도메인 논리의 일부라고 생각합니다.응용 프로그램 서비스는 일반적으로 매우 간단한 흐름을 가져야합니다. 복잡한 응용 프로그램 서비스 흐름은 종종 도메인 논리가 도메인에서 유출되었음을 나타냅니다.
잘 아시다시피, 도메인 모델 은 이러한 방식으로 매우 깨끗하게 유지 되며 도메인 전문가에게는 실제 비즈니스 관련 문제 만 포함되므로 도메인 전문가와 이해하고 토론하기 쉽습니다. 응용 프로그램의 흐름은 , 다른 한편으로는,이다 또한 이 도메인 우려 완화되기 때문에 관리가 훨씬 쉽게, 그리고 간결하고 간단하게된다.
도메인 서비스 : 단일 엔티티에 실제로 맞지 않거나 저장소에 액세스해야하는 메소드는 도메인 서비스 내에 포함됩니다. 도메인 서비스 계층은 자체 도메인 로직을 포함 할 수 있으며 엔터티 및 값 개체만큼 도메인 모델의 일부입니다.
응용 프로그램 서비스 : 응용 프로그램 서비스는 도메인 모델 위에 있으며 응용 프로그램 활동을 조정하는 얇은 계층입니다. 비즈니스 로직을 포함하지 않으며 엔티티의 상태를 보유하지 않습니다. 그러나 비즈니스 워크 플로 트랜잭션의 상태를 저장할 수 있습니다. 응용 프로그램 서비스를 사용하여 요청-응답 메시징 패턴을 사용하여 도메인 모델에 API를 제공합니다.
Millett, C (2010). 전문 ASP.NET 디자인 패턴. 와일리 출판. 92.
도메인 서비스 : Aggregate Root의 일부가 아닌 비즈니스 로직 을 표현하는 서비스입니다 .
2 개의 집계가 있습니다.
Product
이름과 가격이 포함되어 있습니다.Purchase
여기에는 구매 날짜, 당시 수량 및 제품 가격으로 주문한 제품 목록 및 결제 방법이 포함됩니다.Checkout
이 두 모델 중 하나의 일부가 아니며 비즈니스에서 개념입니다.
Checkout
는 모든 제품을 가져와 총 가격을 계산하고 PaymentService
인프라의 구현 부분으로 다른 도메인 서비스 를 호출하여 총액을 지불 한 다음로 변환하는 도메인 서비스로 생성 될 수 있습니다 Purchase
.응용 프로그램 서비스 : 도메인 방법 을 "오케스트레이션" 하거나 연습 하는 서비스입니다 . 이것은 컨트롤러처럼 간단 할 수 있습니다.
이곳은 일반적으로 수행하는 곳입니다.
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);
}
여기서 Product
고유한지 확인하는 등의 유효성 검사를 수행 할 수 있습니다 . 하지 않으면 Product
되는 독특한이 불변 인 그 호출 할 수있는 도메인 서비스의 일부가되어야 UniqueProductChecker
그것의 일부가 될 수 없기 때문에 Product
클래스와는 여러 집계와 상호 작용합니다.
다음은 DDD 프로젝트의 완전한 예입니다. https://github.com/VaughnVernon/IDDD_Samples
많은 응용 프로그램 서비스 예제와 몇 가지 도메인 서비스를 찾을 수 있습니다
도메인 서비스 를 도메인 객체에서 비즈니스 로직 또는 비즈니스 규칙 관련 로직을 구현하는 객체로 생각하면 이 로직은 동일한 도메인 객체에 맞추기가 어렵고 도메인 서비스의 상태 변경을 유발하지 않습니다 (도메인 서비스는없는 객체입니다) 비즈니스 의미가있는 상태가없는 "상태"이상) 그러나 결국 작동하는 도메인 개체의 상태 만 변경합니다.
동안 응용 프로그램 서비스의 사용자 상호 작용, 입력 유효성 검사가 아닌 비즈니스에 있지만 다른 문제와 관련된 로직으로 구현 실용적 레벨 로직 : 인증, 보안 .. 등등 이메일을 보내, 그리고 자신을 제한 단순히 도메인 객체에 의해 노출되는 서비스를 사용할 수 있습니다.
예를 들어 목적을 설명하기 위해서만 생각한 시나리오는 다음과 같습니다. 우리는 간단한 조작을 실행하는 아주 작은 domotic 유틸리티 앱을 구현해야합니다. 즉, 누군가가 집 방 문을 열 때 조명을 켭니다. 방에서 나가는 문을 닫을 때 불을 끄고 끄십시오. "
우리는이 도메인 엔티티를 생각을 많이 단순화 : Door
와 Lamp
, 그들 각각은 2 주, respectevely이 open/closed
와 on/off
그들에 상태 변경을 작동, 특정 방법을.
이 경우 누군가가 문을 열고 외부에서 문을 열 때 조명을 켜는 특정 작업을 실행하는 도메인 서비스가 필요합니다 . 문과 램프 개체는 우리가 적합하다고 생각하는 방식으로이 논리를 구현할 수 없기 때문입니다 그들의 본성에 .
우리는 우리의 도메인 서비스를 호출 할 수 있습니다 DomoticDomainService
: 2 개 메소드를 구현 OpenTheDoorAndTurnOnTheLight
하고 CloseTheDoorAndTurnOffTheLight
이 두 방법은 respectevely 두 개체의 상태 변경 Door
및 Lamp
에를 open/on
하고 closed/off
.
방에서 시작하거나 종료의 상태는 우리가 전화 수, 도메인 서비스 개체 및 중 하나를 도메인 객체에 존재하지 않는,하지만 응용 프로그램 서비스에서 간단한 사용자 상호 작용으로 구현 될 것이다 HouseService
, 그 구현 일부 이벤트 핸들러로 onOpenRoom1DoorToEnter
그리고 onCloseRoom1DoorToExit
, 그래서 각 방에 (이 목적을 설명하기위한 유일한 예입니다 ..) , 그 각각 호출 도메인 서비스 방법에 대한 관심이 참석 동작을 실행하는 것 (우리가 실체 고려하지 않은 Room
단지 예입니다 때문에) .
잘 설계된 실제 응용 프로그램이었던이 예는 도메인 서비스가 무엇이며 응용 프로그램 서비스와의 차이점을 설명하는 유일한 목적을 가지고 있습니다 (명확하고 유용하기를 바랍니다).