8. 8 / 문서의 제목
Domain Concept – 할인 규칙
Rule Sequence Rule
Time Rule
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
10회 상영인 경우
9. 9 / 문서의 제목
Domain Concept –할인 정책 + 할인 규칙
Movie Discount Rule
1 0..1 1 1..*
10. 10 / 문서의 제목
10회 상영인 경우
Domain Concept –할인 정책 + 할인 규칙
Movie Discount Rule
1 0..1 1 1..*
이끼
8000원
Amount DC
800원
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
11. 11 / 문서의 제목
10회 상영인 경우
Domain Concept –할인 적용
이끼
8000원
Amount DC
800원
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
상영정보
2010년 12월 23일 목요일
18:00 ~ 20:00(7회차)
12. 12 / 문서의 제목
10회 상영인 경우
Domain Concept –할인 적용
이끼
8000원
Amount DC
800원
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
상영정보
2010년 12월 23일 목요일
18:00 ~ 20:00(7회차)
7,200
13. 13 / 문서의 제목
Domain Concept –예매
Reservation
이끼
2010년 12월 23일 (목)
7회 6:00(오후) – 8:00(오후)
2명
16,000원
14,400원
제 목
상영 정보
인 원
정 가
결재 금액
16. 16 / 문서의 제목
데이터 모델
MOVIE
ID
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
RESERVATION
ID
CUSTOMER_ID(FK)
SHOWING_ID(FK)
FEE_AMOUNT
FEE_CURRENCY
AUDIENCE_COUNT
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
DISCOUNT
MOVIE_ID(FK)
DISCOUNT_TYPE
FEE_AMOUNT
FEE_CURRENCY
PERCENT
SHOWING
ID
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
CUSTOMER
ID
CUSTOMER_ID
NAME
17. 17 / 문서의 제목
또 다른 데이터 표현 – Anemic Domain Model
Movie
id
title
runningTime
fee
Reservation
id
customerId
showingId
Amounr
audienceCount
Rule
id
discountId
position
ruleType
dayOfWeek
startTime
endTime
sequence
Discount
movieId
discountType
amount
percent
Showing
id
movieId
sequence
showingTime
Customer
Id
customerId
name
18. 18 / 문서의 제목
초기 데이터
ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
1 이끼 120 8000 KRW
MOVIE
MOVIE_ID DISCOUNTYPE FEE_AMOUNT FEE_ACURRENCY PERCENT
1 A 800 KRW NULL
DISCOUNT
ID DISCOUNT_ID POSITION RULE_TYPE DAY_OF_WEEK
1 1 0 S NULL
RULE
START_TIME
NULL
END_TIME
NULL
SEQUENCE
1
2 1 1 S NULL NULL NULL 10
3 1 2 T 2 10:00 12:00 NULL
4 1 3 T 5 18:00 21:00 NULL
ID MOVIE_ID SEQUENCE SHOWING_TIME
1 1 7 2010-12-23 18:00
SHOWING
20. 20 / 문서의 제목
예매 처리 Service
<<interface>>
MovieDAO
<<interface>>
ReservationService
reserveShowing(customerId, showingId, audienceCount)
ReservationServiceImpl
reserveShowing(customerId, showingId, audienceCount)
<<interface>>
DiscountDAO
<<interface>>
RuleDAO
<<interface>>
ShowingDAO
<<interface>>
ReservationDAO
21. 21 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
① 데이터베이스로부터 Movie와 Showing 정보 로딩
② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
④ Reservation 생성 후 데이터베이스 저장
}
Algorithm or Process
22. 22 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
④ Reservation 생성 후 데이터베이스 저장
}
① 데이터베이스로부터 Movie와 Showing 정보 로딩
23. 23 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
④ Reservation 생성 후 데이터베이스 저장
}
private Rule findRule(Showing showing, Movie movie) {
for(Rule each : ruleDAO.selectRules(movie.getId())) {
if (each.isAccepted(showing, movie)) {
return each;
}
}
return null;
}
② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단
24. 24 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
Money fee = movie.getFee();
if (rule != null) {
fee = calculateFee(movie);
}
④ Reservation 생성 후 데이터베이스 저장
}
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
private Money calculateFee(Movie movie) {
Discount discount = discountDAO.selectDiscount(movie.getId());
if (discount.isAmountType()) {
return movie.getFee().minus(Money.wons(discount.getFee()));
} else if (discount.isPercentType()) {
return movie.getFee().minus(
movie.getFee().times(discount.getPercent()));
}
return movie.getFee();
}
25. 25 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
Money fee = movie.getFee();
if (rule != null) {
fee = calculateFee(movie);
}
Reservation result = makeReservation(customerId, showingId, audienceCount, fee);
reservationDAO.insert(result);
return result;
}
④ Reservation 생성 후 데이터베이스 저장
private Reservation makeReservation(int customerId, int showingId,
int audienceCount, Money payment) {
Reservation result = new Reservation();
result.setCustomerId(customerId);
result.setShowingId(showingId);
result.setAudienceCount(audienceCount);
result.setFee(payment);
return result;
}
26. 26 / 문서의 제목
중앙 집중식Centralized 제어 스타일
reserveShowing()
showing = selectShowing()
rules = selectRules()
isAccepted()*
discount = selectDiscount()
isAmountType()
getFee()
new
rules
:Rule
:Showing
DAO
showing
:Showing
:Reservation
Service
:Rule
DAO
:Discount
DAO
discount
:Discount
:Reservation
30. 30 / 문서의 제목
Showing
상영 정보를 알고 있다
예매 생성 책임
예매 생성에 필요한 정보의 EXPERT에게 할당Creator
예매 정보를 생성한다
31. 31 / 문서의 제목
가격 계산 책임
영화 가격 정보를 알고 있는 EXPERT에 할당Information Expert
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
Movie
Customer
Movie
영화정보를 알고 있다
가격을 계산한다
32. 32 / 문서의 제목
Showing
상영 정보를 알고 있다
Movie
영화정보를 알고 있다 DiscountStrategy
할인율 계산 책임
할인율을 적용할 STRATEGY 객체 추가
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
예매 정보를 생성한다
Movie
Customer
가격을 계산한다
33. 33 / 문서의 제목
Showing
상영 정보를 알고 있다
Movie
영화정보를 알고 있다 DiscountStrategy
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
예매 정보를 생성한다
Movie
Customer
가격을 계산한다
할인 여부를 판단할 책임
할인 정책을 판단하기 위한 SPECIFICATION 객체 추가
Rule
할인 정책을 알고 있다
할인 여부를 판단한다
Rule
Showing
34. 34 / 문서의 제목
Rich Domain Model
Customer
Showing
reserve(customer, count):Reservation
Rule
isStatisfiedBy(showing):boolean
Reservation
AmountStrategy PercentStrategy NonDiscountStrategy SequenceRule TimeOfDayRule
DiscountStrategy
calculateFee(showing):Money
Movie
calculateFee(showing):Money
상속inheritance과 다형성polymorphism의 활용
<<create>>
36. 36 / 문서의 제목
public class Showing {
public Reservation reserve(Customer customer, int audienceCount) {
return new Reservation(customer, this, audienceCount);
}
}
public class Reservation {
public Reservation(Customer customer, Showing showing, int audienceCount) {
this.customer = customer;
this.showing = showing;
this.fee = showing.calculateFee().times(audienceCount);
this.audienceCount = audienceCount;
}
}
public class Showing {
public Money calculateFee() {
return movie.calculateFee(this);
}
}
public class Movie {
public Money calculateFee(Showing showing) {
return discountStrategy.calculateFee(showing);
}
}
책임 기반 구현
37. 37 / 문서의 제목
public abstract class DiscountStrategy {
public Money calculateFee(Showing showing) {
for(Rule each : rules) {
if (each.isStatisfiedBy(showing)) {
return getDiscountedFee(showing);
}
}
return showing.getFixedFee();
}
abstract protected Money getDiscountedFee(Showing showing);
public abstract class Rule {
abstract public boolean isStatisfiedBy(Showing showing);
}
public class SequenceRule extends Rule {
public boolean isStatisfiedBy(Showing showing) {
return showing.isSequence(sequence);
}
} public class TimeOfDayRule extends Rule {
public boolean isStatisfiedBy(Showing showing) {
return showing.isPlayingOn(dayOfWeek) &&
Interval.closed(startTime, endTime)
.includes(showing.getPlayngInterval());
}
}
책임 기반 구현
38. 38 / 문서의 제목
public abstract class DiscountStrategy {
public Money calculateFee(Showing showing) {
for(Rule each : rules) {
if (each.isStatisfiedBy(showing)) {
return getDiscountedFee(showing);
}
}
return showing.getFixedFee();
}
abstract protected Money getDiscountedFee(Showing showing);
책임 기반 구현
public class AmountDiscountStrategy extends DiscountStrategy {
protected Money getDiscountedFee(Showing showing) {
return showing.getFixedFee().minus(discountAmount);
}
}
public class NonDiscountStrategy extends DiscountStrategy {
protected Money getDiscountedFee(Showing showing) {
return showing.getFixedFee();
}
}
public class PercentDiscountStrategy extends DiscountStrategy {
protected Money getDiscountedFee(Showing showing) {
return showing.getFixedFee().minus(showing.getFixedFee().times(percent));
}
}
39. 39 / 문서의 제목
위임식delegated, 분산식dispersed 제어 스타일
:Reservation :Movie
reserve()
new
:Showing
calculateFee()
calculateFee()
:DiscountStrategy :Rule
calculateFee()
isStatisfied()*
53. 53 / 문서의 제목
POJO의 3대 요소
Dependency
Injection
Aspect-Oriented
Programming
Annotation
54. 54 / 문서의 제목
비침투적인Non-Intrusive 프레임워크
POJO 개발을 위한 젂제조건
Lightweight Framework
55. 55 / 문서의 제목
Dependency Injection
객체 간의 의졲성 관리 이슈로부터 도메인 레이어 보호
구성-사용 분리 원리the principle of separating configuration from use
<<interface>>
ReservationService
reserveShowing(customerId, showingId, audienceCount)
ReservationServiceImpl
reserveShowing(customerId, showingId, audienceCount)
<<interface>>
CustomerRepository
CustomerRepositoryImpl
57. 57 / 문서의 제목
Impedance Mismatch
객체 모델과 DB 스키마 간의 불일치
객체 모델과 DB 스키마 간의 변환 계층 필요
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
DISCOUNT
MOVIE_ID(FK)
DISCOUNT_TYPE
FEE_AMOUNT
FEE_CURRENCY
PERCENT
Rule
Amount
Strategy
Percent
Strategy
NonDiscount
Strategy
Sequence
Rule
TimeOfDay
Rule
DiscountStrategy
58. 58 / 문서의 제목
DATA MAPPER
객체 모델과 DB 스키마 간의 독립성 유지
도메인 객체는 DB에 대해 독립적
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
Rule
SequenceRule TimeOfDayRule
RuleMapper
insert
Update
delete
64. 64 / 문서의 제목
Rich Domain Model
설계 관점이지 기술 관점이 아님
훌륭한 객체 지향 설계 지침을 따를 것
65. 65 / 문서의 제목
그러나 기술적인 제약 사항 역시 중요
비침투적인 프레임워크를 사용하라
프레임워크의 제약 사항을 파악하라
프레임워크의 제약 사항에 따라 구현 가능하도록 아키텍처를 수정하라
가지고 있는 도구 또한 아키텍처에 영향을 준다는 사실을 알 수 있다. 때로는 아키
텍처를 바탕으로 도구를 선택할 수 있으며, 이롞적으로는 그것이 올바른 방법이다.
그러나 실제로는 도구에 아키텍처를 맞추어야 한다.
- Martin Fowler
66. 66 / 문서의 제목
Rich Domain Model을 자제해야 하는 경우
객체 지향 분석/설계 경험이 부족한 경우
비침투적인 프레임워크를 사용할 수 없는 경우
비침투적인 프레임워크에 대한 경험이 부족한 경우
O/R Mapper를 사용할 수 없는 경우
비즈니스 로직이 단순하고 개발 기간이 짧은 경우