2010-05-24 6 views
26

대규모 웹 사이트 구현을 위해 도메인 기반 디자인을 따르고 있습니다.도메인 기반 디자인을 사용하여 매우 큰 개체를 피하는 방법

그러나 도메인 객체에 비헤이비어를 적용하면 몇 가지 매우 큰 클래스로 끝납니다.

예를 들어 WebsiteUser 객체에는 많은 메소드가 있습니다. 암호 처리, 주문 내역, 환불, 고객 세분화. 이러한 모든 방법은 사용자와 직접 관련이 있습니다. 이러한 메소드 중 상당수는 내부적으로 다른 자식 객체에 위임하지만
여전히 매우 큰 클래스가 생성됩니다.

나는 많은 자식 개체가 노출되는 것을 피하려고합니다. 예 : user.getOrderHistory(). getLatestOrder().

이 문제를 방지하기 위해 어떤 다른 전략을 사용할 수 있습니까?

답변

2

동일한 문제가 발생하여 하위 "관리자"개체를 사용하는 것이 가장 적합한 해결책이라는 것을 알았습니다.

예를 들어, 귀하의 경우, 당신은 할 수 있습니다

User u = ...; 
OrderHistoryManager histMan = user.getOrderHistoryManager(); 

그런 다음 당신은 당신이 원하는 무엇이든을 위해 histMan를 사용할 수 있습니다. 분명히 당신은 이것에 대해 생각했지만, 왜 당신이 그것을 피하고 싶어하는지 모르겠습니다. 그것은 당신이 너무 많이하는 것처럼 보이는 사물을 가질 때 염려를 분리시킵니다.

이렇게 생각하십시오. "인간"개체가있는 경우 chew() 메서드를 구현해야합니다. Human 오브젝트 또는 Mouth 하위 오브젝트에 넣을 수 있습니까?

19

표시되는 문제는 도메인 기반 디자인에 의해 야기 된 것이 아니라 우려의 분리로 인한 것입니다. 도메인 기반 디자인은 단순히 데이터와 동작을 함께 배치하는 것이 아닙니다.

제가 권하는 첫 번째 것은 하루 정도 걸리고 Info-Q에서 무료로 다운로드 할 수있는 Domain Driven Design Quickly을 읽는 것입니다. 여기서는 엔티티, 값 객체, 서비스, 리포지토리 및 팩토리와 같은 여러 유형의 도메인 객체에 대한 개요를 제공합니다.

내가 권하고 싶은 두 번째 것은 Single Responsibility Principle에서 읽는 것입니다.

세 번째로 추천하는 것은 Test Driven Development에 자신을 담그는 것입니다. 테스트를 작성하여 처음부터 디자인을 배우는 것이 반드시 디자인을 훌륭하게 만들지는 못하지만 느슨하게 결합 된 디자인으로 안내하고 이전에 디자인 문제를 드러내는 경향이 있습니다.

예를 들어, WebsiteUser는 분명히 너무 많은 책임이 있습니다. 사실 사용자가 일반적으로 ISecurityPrincipal으로 표시되기 때문에 WebsiteUser이 필요하지 않을 수도 있습니다.

비즈니스 컨텍스트가 부족하여 디자인에 어떻게 접근해야하는지 정확하게 설명하는 것이 어렵지만, 먼저 시스템에있는 주요 명사를 나타내는 인덱스 카드를 만들어 두뇌 공격을하는 것이 좋습니다. (예 : 고객, 주문, 영수증, 제품 등). 후보 클래스 이름을 맨 위에 적고, 왼쪽에있는 클래스의 고유 한 책임은 무엇인지, 그리고 오른쪽에있는 클래스와 협력하십시오. 일부 동작이 객체에 속한 것처럼 느껴지지 않는 경우, 이는 아마도 좋은 서비스 후보 (즉, AuthenticationService) 일 것입니다.대학과 함께 테이블에 카드를 펼치고 토론하십시오. 이것이 실제로 브레인 스토밍 디자인 연습으로 의도 된 것이므로 너무 많이 사용하지 마십시오. 화이트 보드를 사용하는 것보다 때때로 작업을 수행하는 것이 약간 쉬울 수 있습니다.

장기적으로 보면 에릭 에반스가 책 Domain Driven Design을 실제로 받아야합니다. 그것은 큰 읽을 거리지만, 당신의 시간 가치가 있습니다. 언어 환경에 따라 Agile Software Development, Principles, Patterns, and Practices 또는 Agile Principles, Patterns, and Practices in C# 중 하나를 선택하는 것이 좋습니다.

+0

이 의견을 보내 주셔서 감사합니다. Evans의 책을 읽었습니다. 문제는 하나의 엔티티에 많은 공동 작업자가있는 경우입니다. 예 : 웹 사이트 사용자 (또는 사용자)는 최신 주문, 첫 번째 주문, 장바구니, 암호 등을 가지고 있습니다.이 모든 것은 웹 사이트 사용자와 직접 관련이 있습니다. – Pablojim

+1

인증, 보류 중 주문 상태 (쇼핑 카트) 및 주문 내역은 별개로 우려됩니다. 인증을 IAuthenticationService로 가져 와서 IOrderHistoryRepository (또는 IOrderHistoryService)를 만들어 주어진 사용자의 주문 내역을 검색하는 동작을 캡슐화하는 것이 좋습니다. –

2

매우 간단한 규칙은 "클래스의 대부분의 메서드는 클래스의 인스턴스 변수를 사용해야합니다."이 규칙을 따르면 클래스가 자동으로 올바른 크기가됩니다.

+0

흥미로운 관찰입니다. 링크를 제공 할 수 있습니까? – ya23

+0

그것은 기본적으로 SRP를 기억하는 더 간단한 방법입니다 - 나는 그것을 oo 책 중 하나에서 읽었지 만 정말 재미 있고 그것이 내 마음 속에 갇혀 있음을 발견했습니다. – OpenSource

+0

이것은 높은 응집력이라고도합니다. – beluchin

2

반전을 고려할 수 있습니다. 예를 들어, 고객은 Order 속성 (또는 주문 내역)을 보유 할 필요가 없습니다. 고객 클래스에서 고객을 제외시킬 수 있습니다.

 
public void doSomethingWithOrders(Customer customer, Calendar from, Calendar to) { 
    List = orderService.getOrders(customer, from, to); 
    for (Order order : orders) { 
     order.doSomething(); 
    } 
} 

이 '패자'커플 링이지만, 여전히 당신은 고객에게 속한 모든 주문을 얻을 수 있습니다 : 그래서 그 대신

 
public void doSomethingWithOrders(Customer customer, Calendar from, Calendar to) { 
    List = customer.getOrders(from, to); 
    for (Order order : orders) { 
     order.doSomething(); 
    } 
} 

의 대신 할 수 있습니다. 위의 내용을 참조하는 올바른 이름과 링크가있는 나보다 똑똑한 사람들이있을 것이라고 확신합니다.

9

실제 인간은 많은 책임을지고 있지만 God object anti-pattern으로 향하고 있습니다. 다른 사람이 암시 한 것처럼

, 별도의 저장소 및/또는 도메인 서비스에 그 책임을 추출한다. 예컨대 :

SecurityService.Authenticate(credentials, customer) 
OrderRepository.GetOrderHistoryFor(Customer) 
RefundsService.StartRefundProcess(order) 

명명 규칙에 구체적으로 (즉, 대신 OrderManager의, OrderRepository 또는 는 OrderService 사용)

당신은이 문제로 실행했습니다 때문에 편리. 즉 WebsiteUser집합 루트으로 처리하고이를 통해 모든 항목에 액세스하는 것이 편리합니다. 당신이 선명도 대신 편리 의에 더 중점을 배치하면

, 이러한 우려를 분리하는 데 도움이됩니다. 불행히도 팀 구성원이 이제는 새로운 서비스에 대해 알고 있어야 함을 의미합니다.

그것을 생각하는 또 다른 방법 : 엔티티은 (우리가 저장소를 사용하는 이유입니다) 자신의 지속성을 수행하지 말아야하는 것처럼, 당신의 WebsiteUser 처리하지 않아야 환불/분할/등.

희망 하시겠습니까?

1

저는 귀하의 문제가 실제로 Bounded Contexts와 관련이 있다고 생각합니다.내가보기에 "암호, 주문 내역, 환불, 고객 세분화"를 다루는 경우, 이들 각각은 한정된 맥락 일 수 있습니다. 따라서 웹 사이트 사용자를 문맥에 해당하는 여러 항목으로 분할하는 것을 고려할 수 있습니다. 중복이 발생할 수 있지만 도메인에 중점을두고 여러 책임을지는 매우 큰 클래스를 제거하십시오.

+0

+1 이것은 DCI가있는 DDD와 비슷할 것입니다. 시스템이 무엇인지 시스템이 무엇인지 구분하십시오. – Gordon

관련 문제