본문 바로가기

Dev.../소프트웨어 아키텍처

[SA강좌] Part 4-7 Domain Model 패턴

도메인 모델(Domain Model) 패턴

도메인 모델 패턴의 정의

도메인 모델 패턴은 행동과 데이터가 협력하는 도메인의 개체 모델 패턴이다.

그림 -10. 도메인 모델 패턴의 구조

도메인 모델 패턴의 설명

나쁜 비즈니스 로직은 매우 복잡하다. 비즈니스 규칙과 로직은 많은 다른 사례와 행동에 편향적인 설명을 한다. 도메인 모델 패턴은 내부적으로 연결된 개체들의 망을 생성한다. 주문 양식에 있는 협력체 만큼이나 크거나 단일 라인 만큼 작은 각 개체는 몇몇 의미있는 개체를 표현한다.

도메인 모델 패턴은 언제 사용하는가?

만일 도메인 모델 패턴 사용을 생각한다면, 데이터베이스와 상호작용을 위한 첫 번째 선택은 데이터 매핑 패턴이다. 이 패턴은 데이터베이스에서 도메인 모델 패턴이 독립되도록 유지하고, 도메인 모델과 데이터베이스 스키마 차이가 발생하는 사례를 조작하기 위한 접근을 제공한다.

도메인 모델을 사용할 때, 서비스 레이어 패턴을 고려해야 한다. 이 패턴은 도메인 모델 패턴이 API에서 멀어지도록 한다.

도메인 모델 패턴의 적용 예제 : 세금 계산

직접적인 인식은 예제가 가지고 있는 행동과 데이터의 모든 클래스를 인식하는 것이다. 만일 개체의 값이 임의 데이트를 인식하면, 세금 인식 클래스는 검색을 위한 간단한 메서드를 아래와 같이 포함하게 된다.

class RevenueRecognition ...

private Money amount;

private MfDate date;

public RevenueRecognition(Money amount, MfDate date) {

this.amount = amount;

this.date = date;

}

public Money getAmount() {

return amount;

}

boolean isRecognizable(MfDate asOf) {

return asOf.after(date) || asOf.equals(date);

}

얼마나 많은 세금이 특정 일자에 인식 되었는지를 계산하는 것은 계약과 세금 인식 클래스를 포함한다.

class Contract ...

 

private List revenueRecognitions = new ArrayList();

public Money recognizedRevenue(MfDate asOf) {

Money result = Money.dollars(0);

Iterator it = revenueRecognitions.iterator();

while (it.hasNext()) {

RevenueRecognition r = (RevenueRecognition) it.next();

if (r.isRecognizableby(asOf))

result = result.getAmount();

}

return result;

}

도메인 모델에서 공통점을 찾기는 것은 얼마나 간단한 작업들이 다중 클래스들과 상호작용을 하는지를 인식하는 것이다.

class Contract ...

 

private Product product;

private Money revenue;

private MfDate whenSigned;

private Long id;

public Contract(Product product, Money revenue, MfDate whenSigned) {

this.product = product;

this.revenue = revenue;

this.whenSigned = whensinged;

}

 

class Product ...

 

private String name;

private RecognitionStrategy recognitionStrategy;

public Product(String name, RecognitionStrategy recognitionStrategy) {

this.name = name;

this.recognitionStrategy = recognitionStrategy;

}

public static Product newWordProcessor(String name) [

return new Product(name, new CompleteRecognitionStrategy());

}

public static Product newSpreadsheet(String name) {

return new Product(name, new TreeWayRecognitionStrategy(60,90));

}

public static Product newDatabase(String name) {

return new Product(name, new TreeWayRecognitionStrategy(30,60));

}

 

class RecognitionStrategy ...

 

abstract void calculateRevenueRecognitions(Contract contract);

 

class CompleteRecognitionStrategy ...

 

void calculateRevenueRecognitions(Contract contract) {

contract.addRevenueRecognitions(new RevenueRecognition(contract.getRevenue(),

contract.getWhenSigned());

}

 

class TreeWayRecognitionStrategy ...

 

 

private int firstRecognitionOffset;

private int secondRecognitionOffset;

public ThreeWayRecognitionStrategy(int firstRecognitionOffset,

int secondRecognitionOffset)

{

this.firstRecognitionOffset = firstRecognitionOffset;

this.secondRecognitionOffset = seondRecognitionOffset;

}

void calculateRevenueRecognitions(Contract contract) {

Money[] allocation = contract.getRevnue().allocate(3);

contract.addRevenueRecognition(new RevenueRecognition

(allocation[0], contract.getWhenSigned());

contract.addRevenueRecognition(new RevenueRecognition

(allocation[1], contract.getWhenSigned().addDays(firstRecognitionOffset)));

contract.addRevenueRecognition(new RevenueRecognition

(allocation[2], contract.getWhenSigned().addDays(firstRecognitionOffset)));

}

 

class Tester ...

 

private Product word = Product.newWordProcessor("Thinking Word");

private Product calc = Product.newSpreadsheet("Thinking Calc");

private Product db = Product.newDatabase("Thinking DB");

일단 모든 것이 설정되면, 세금 인식 계산은 전략 서브클래스의 임의 지식을 요청한다.

 

class Contract ...

 

public void calculateRecognitions() {

product.calculateRevenueRecognition(this);

}

 

class Product ...

 

void calculateRevenueRecognition(Contract contract) {

recognitionStrategy.calculateRevenueRecognition(contract);

}