11

엔터프라이즈 애플리케이션 아키텍처 패턴에서 Martin Fowler는 도메인 논리 구성을위한 두 가지 패턴 인 Domain ModelService Layer에 대해 설명합니다. 도메인 모델 패턴은 모델 (ORM을 사용하여 데이터베이스에서 조회 한 객체)이 비즈니스 로직을 포함하는 "순수 OOP"접근 방식입니다 (하지만 다른 클래스의 로직에만 위임 한 경우 일 수도 있음).EA의 P에있는 도메인 모델 및 서비스 계층 패턴

A sample Domain Model

서비스 계층 패턴은 도메인 모델 패턴 같지만 수행 할 수있는 사업 운영을 포함하는 앞의 얇은 층. MVC에서 컨트롤러는 대부분 서비스 레이어와 상호 작용합니다. 가장 잘 설계된 MVC 웹 애플리케이션이이 패턴을 사용한다고 생각합니다.

A sample Service Layer

이제 내 질문에. Martin은 도메인 모델 접근 방식이 객체 지향 접근 방식이 더 좋으므로 더 좋습니다. 내 경험상, 실제로 구현하는 것은 매우 어렵습니다 (보기 : 불가능).

위의 첫 번째 다이어그램에서 주어진 예를 선택하십시오. 두 개의 '개체'ContractProduct이 있습니다. 이들은 mapper를 사용하여 데이터베이스에 유지됩니다. 이 예에는 RecognitionStrategy이 있습니다. Martin은 실제 비즈니스 로직을 포함하는이 전략에 위임하는 방법을 엔터티 자체에 두었습니다. 클라이언트는 contract.calculateRecognitions 또는 contract.recognizedRevenue(someDate)을 사용하여이 계산을 수행합니다. 비슷한 디자인을 구현할 때는 보통 클라이언트 인터페이스를 strategy.calculateRecognitions(contract)strategy.recognizedRevenue(contract, someDate)으로 작성합니다. 이로 인해 전략과 계약을 조정하는 데 필요한 서비스 계층이 만들어집니다. 사용 된 구체적인 전략이 서비스에 주입됩니다.

마틴의 접근 방식은 확실히 디자인의 관점에서 더 매력적이지만, 설치 주위의 작업은 훨씬 더 어렵다하십시오 Product이 고통 인스턴스화 할 때

  1. 이 전략에 전달. 사용할 구체적인 서비스로 카레트 된 팩토리를 통해 Product을 생성해야하며,이를 생성 할 때 엔터티로 전달합니다.
  2. 데이터베이스 액세스에 대한 세밀한 제어가 덜합니다. ORM 설정에 따라 Product에 위임 한 ContractProduct에 대한 쿼리를 수행 할 수 있습니다. 을로드했지만 contract.calculateRecognitions()을 호출 할 의도가 없으면 매퍼 (또는 ORM)에 Product을로드하는 것이 지나치게 위태로울 수 있습니다. 내 접근 방식은 엔티티가해서는 안되는 데이터베이스 추상화 계층에 대한 지식을 가지고 있기 때문에보다 세분화 된 제어를 제공합니다.

실제로 여기에 열거되지 않은 더 많은 고통 점이 있다고 확신합니다.

순수 데이터 모델 패턴을 사용하도록 확신 할 수있는 마틴의 접근법에는 어떤 이점이 있습니까?

답변

1

도메인 모델은 개체를 대표 할뿐만 아니라 빈혈보다 행동이 좋습니다. 그것에 붙어 행동 때문에. 기본 예는 dog입니다. bark, breatheeat입니다. 서비스 계층에서 모델은 BarkHandlerBreatheHandler으로 향상되었습니다.

도메인 모델 접근 방식은 기본적으로 UML 디자인 패턴에 의해 지원됩니다.My previous answer here. 빈 도메인 모델 접근법 (서비스 계층)에서는 UML 다이어그램 (클래스 다이어그램)을 만드는 것이 어렵고, 만들 수 있다고하더라도 공식적으로 허용되지 않으므로 사람들이 다른 해석을 할 수 있습니다.

디자인 관점에서 볼 때 서비스 계층도 "independent"이거나 분리되어 있습니다. 빈혈 도메인 모델 class을 보면 도메인 모델과 관련된 동작 (예 : 저장)을 찾을 수 없습니다. 도메인 모델의 특정 동작을 찾으려면 전체 프로젝트를 검색해야합니다. 리치 도메인 모델에서는 도메인 모델 자체의 동작 흔적을 알 수 있습니다.

리치 도메인 모델에는 해당 속성에 대한 액세스 수정 자 (public, private, protected)가 있습니다. 재산의 가시성은 물론. 예를 들어 제출 후 상태를 변경하려는 경우 속성에 public에 대한 액세스 권한을 부여 할 수 있지만 액세스 권한은 protected으로 설정할 수 있습니다. 서비스 계층에서 액세스를 설정하려면 public으로 설정하거나 internal protected으로 속여서 제출자가 internal access을 통해 속성을 직접 변경하도록해야합니다. 그러나 그것은 더 복잡합니다.

그러나 리치 도메인 모델 does not have the flexibilityanemic domain model입니다. 상속을 사용하지 않으면 도메인 모델의 클래스를 변경하지 않고 모델에 동작을 추가 할 수 없습니다. 빈혈 도메인 모델에서는 런타임 수준에서 스왑 할 수도 있습니다.

6

첫 번째 사항에 대해서는 Product 객체를 인스턴스화 할 때 종속성 주입을 사용해야합니다. 객체 그래프 구축은 책임이 있으며 비즈니스 논리와 혼용해서는 안됩니다 (단일 책임 원칙).

두 번째 사항에 대해서는 공급 업체 특성이 데이터 액세스 계층 뒤에 숨겨져 있어야하며 DAO 또는 리포지토리가 필요에 따라 개체를 반환해야합니다.

제품을 강하게로드하는 것 (관계가 1 대 다수 인 상황에서)에 대한 대안은 제품 DAO를 계약 오브젝트에 주입하는 것입니다. 이 방법을 사용하면 필요한 경우 계약과 관련된 제품을 얻을 수 있습니다 (아마도 내부적으로 사용할 수있는 게터로).

물론 완벽한 솔루션이 존재하지 않으며 항상 상충 관계가 있습니다. 응용 분야에 더 잘 맞는 접근 방식을 평가하는 건축가로서의 당신의 직업.

개인적으로 나는 서비스 클래스에 너무 많이 의존하는 것이 잘 정의 된 책임이 없으며 일반적으로 테스트하기가 어렵다는 거대한 클래스를 생성하는 경향이 있다는 것을 알게되었습니다.

도메인 모델 접근법을 사용할 때의 장점은 명확한 분리와 테스트 가능성의 증가입니다.

마지막으로 "순수한"도메인 모델 접근 방식을 사용할 필요가 없습니다. 도메인 모델과 서비스 계층은 함께 사용될 것으로 예상됩니다. 도메인 모델 엔티티는 경계 내에있는 동작을 다루며 서비스 계층 커버 로직은 도메인 엔티티에 속하지 않습니다.

일부 추가 참조 흥미로운

Domain Driven Design and Development In Practice - An interesting article on DDD

Dependency Injection, Design patterns using Spring and Guice - Great book on dependency injection

안부를 찾을 수 있습니다,

엠마누엘 루이스 Lariguet 벨 드라

관련 문제