부풀린 도메인 객체 피하기


12

DDD 접근 방식을 사용하여 데이터를 부풀린 서비스 계층에서 도메인 계층으로 이동하려고합니다. 우리는 현재 서비스에 많은 비즈니스 로직을 가지고 있으며, 이는 여러 곳에 퍼져 있으며 상속의 혜택을받지 않습니다.

우리는 대부분의 작업에 초점을 맞춘 중앙 도메인 클래스를 가지고 있습니다-무역. Trade 객체는 가격 책정 방법, 위험 평가 방법, 자체 검증 방법 등을 알게됩니다. 그런 다음 조건을 다형성으로 대체 할 수 있습니다. 예 : SimpleTrade는 한 가지 방법으로 가격을 책정하지만 ComplexTrade는 다른 방법으로 가격을 책정합니다.

그러나 이것이 트레이드 클래스를 팽창 시킬까 걱정됩니다. 실제로 자체 처리를 담당해야하지만 더 많은 기능이 추가되면 클래스 크기가 기하 급수적으로 증가합니다.

그래서 우리는 선택할 수 있습니다 :

  1. 처리 클래스를 Trade 클래스에 넣습니다. 처리 논리는 이제 거래 유형에 따라 다형성이지만, 거래 클래스는 이제 여러 책임 (가격 책정, 위험 등)을 가지며
  2. 처리 로직을 TradePricingService와 같은 다른 클래스에 넣습니다. 더 이상 거래 상속 트리에서 다형성이 아니지만 클래스는 더 작고 테스트하기 쉽습니다.

제안 된 접근법은 무엇입니까?


문제 없습니다-마이그레이션을 수락하게되어 기쁩니다!

1
반대를 조심하십시오 : martinfowler.com/bliki/AnemicDomainModel.html
TrueWill

1
"더 많은 기능이 추가됨에 따라 클래스 크기가 기하 급수적으로 증가 할 것입니다."
Michael Borgwardt

@Piskvor 그건 그냥 바보
아르 니스 Lapsa

@Arnis L .: 당신의 사려 깊은 의견에 감사드립니다. 이것은 내 의견과 함께 "stackoverflow.com 11 월 22 일 22:19에서 마이그레이션 됨"입니다. 나는 "이것은 프로그래머가 더 좋을 것이다"라는 내 의견을 제거했다. 이제 추가 할 것이 있습니까, 아니면 당신이 표현하고자하는 유일한 아이디어입니까?
Piskvor 건물 왼쪽

답변:


8

Domain Driven을 사용하는 경우 Trade 클래스를 집계 루트로 취급하고 해당 책임을 다른 클래스로 분류하십시오.

가격과 위험의 각 조합에 대해 거래 서브 클래스로 끝나지 않기 위해, 거래에는 가격 및 위험 오브젝트 (구성)가 포함될 수 있습니다. Price 및 Risk 개체는 실제 계산을 수행하지만 Trade를 제외한 모든 클래스에는 표시되지 않습니다. 새로운 클래스를 외부 세계에 노출시키지 않으면 서 거래 규모를 줄입니다.

상속 트리가 크지 않도록 컴포지션을 사용하십시오. 상속이 너무 많으면 실제로 모델에 맞지 않는 동작으로 구두를 치는 상황이 발생할 수 있습니다. 그러한 책임을 새로운 클래스로 끌어내는 것이 좋습니다.


동의한다. 문제를 모형화하지 않고 솔루션을 구성하는 행동 (가격, 위험 평가) 측면에서 객체를 생각하면 이러한 모 놀리 식 클래스를 피할 수 있습니다.
개렛 홀

또한 동의합니다. 작문, 특정 단일 책임, 개인 메소드의 제한된 사용, 많은 행복한 인터페이스 등을 포함한 많은 소규모 수업
Ian

4

귀하의 질문은 확실히 전략 패턴을 생각하게합니다 . 그런 다음 전화하는 것과 비슷한 다양한 거래 / 가격 전략을 교환 할 수 있습니다 TradePricingService.

나는 당신이 여기서 얻을 수있는 조언은 상속 대신 구성을 사용하는 것이라고 생각합니다.


2

비슷한 경우에 사용한 한 가지 가능한 솔루션은 어댑터 디자인 패턴입니다 (참조 된 페이지에는 많은 샘플 코드가 포함되어 있음). 주요 방법에 쉽게 액세스 할 수 있도록 위임 디자인 패턴 과 결합되었을 수 있습니다.

기본적으로 거래자 기능을 여러 가지 분리 된 영역으로 나눕니다. 예를 들어 가격, 위험, 유효성 처리는 모두 다른 영역 일 수 있습니다. 각 영역에 대해 각기 다른 영역의 공통 인터페이스 인 서로 다른 필요한 변형의 정확한 기능을 처리하는 별도의 클래스 계층 구조를 구현할 수 있습니다. 그런 다음 기본 Trader 클래스는 가장 기본적인 데이터로 축소되고 필요한 경우 구성 할 수있는 많은 핸들러 객체에 대한 참조입니다. 처럼

interface IPriceCalculator {
  double getPrice(ITrader t);
}
interface ITrader {
  IPriceCalculator getPriceCalculator();
}
class Tracer implements ITrader {
  private IPriceCalculator myPriceCalculator = null;
  IPriceCalculator getPriceCalculator() {
    if (myPriceCalculator == null)
      myPriceCalculator = PriceCalculatorFactory.get(this);
    return myPriceCalculator;
  }
}

이 접근법의 한 가지 주요 장점은 예를 들어 가격과 릭의 가능한 조합이 완전히 분리되어 필요에 따라 결합 될 수 있다는 것입니다. 대부분의 프로그래밍 언어의 단일 스레드 상속에서는 다소 어렵습니다. 사용할 조합의 결정은 심지어 매우 늦게 계산 될 수 있습니다 :-)

나는 보통 어댑터 클래스를 유지하려고 노력한다 IPriceCalculator. 즉, 이러한 클래스는 작성해야하는 인스턴스 수를 줄이기 위해 가능하면 로컬 데이터를 포함하지 않아야합니다. 따라서 일반적으로 getPrice(ITrader)위와 같이 모든 방법에서 주요 적응 객체를 인수로 제공합니다 .


2

도메인에 대해 많이 말할 수는 없지만

우리는 대부분의 작업에 초점을 맞춘 중앙 도메인 클래스를 가지고 있습니다-무역.

... 냄새가 나다. 아마도 클래스의 다른 책임을 스케치하고 결국 다른 집계로 분해하려고합니다. 그런 다음 관련 이해 관계자 / 도메인 전문가의 역할 및 / 또는 관점을 중심으로 집계를 설계합니다. Price와 Risk가 동일한 행동 / 사용 사례에 관련된 경우 아마도 동일한 집계에 속할 수 있습니다. 그러나 분리 된 경우 별도의 집계에 속할 수 있습니다.

아마도 RiskEvaluation 은 특정 수명주기를 가진 도메인의 별도 엔티티 일 수 있습니다 (실제로는 추측 할 수는 없지만 도메인을 알지 못합니다).하지만 핵심은 암시 적 개념을 만드는 것입니다 명시 적이며 동작에 의해 구동되는 것이 아니라 레거시 데이터 결합에 의한 결합 만 피합니다.

일반적으로 예상되는 동작과 관련된 구성 요소의 다른 수명주기에 대해 생각합니다. 그룹화 된 데이터 위에 비헤이비어를 추가하면 부풀어 오른 객체가 만들어집니다. 그러나 기존의 데이터 중심 설계에 따라 데이터가 그룹화되었으므로이를 고수 할 필요가 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.