데이터 중심의 설계 방법
단점
깃허브 chapter 4 - step 1 참조
코드가 더러움.
할인을 적용하는 구현 방식에서 난잡하다고 느낌
할인조건에 대한 책임(행동)의 상태값이 여기저기 흩어져 있는 느낌을 받았다.
step 2 도 할인정책의 상태값이 변경된다면, Screen, Movie, Discountcondition 클래스들에 전체적으로 영향을 미치니 캡슐화가 올바르게 되지 않았다고 볼 수 있다.
또한, ReservationAgency 클래스가 직접 할인 요금을 계산하는 로직을 구현하고 있다보니, 할인 요금을 계산하는데, 할인조건, 영화의 정보등.. 많은 상태값과 클래스에 의존하고 있기 때문에, 변경에 매우 취약하다.
책임 중심의 설계
행동(책임)중심으로 설계를 하자.
꼭 필요한 행동 중심으로 인터페이스나 추상 클래스를 생성하여 캡슐화하자!
캡슐화하지 않으면 객체사이의 결합도가 증가, 응집도가 낮아져서 변경이 취약함
제대로 캡슐화하기
개별적으로 속성을 private로 설정하고 get, set으로 외부객체가 접근하게 하는건 올바른 캡슐화가 아니다.
만약, Reactangle이라는 클래스가 있고 속성을 width, height를 가진다고 했을때,
Calculate 클래스에서는 Reactangle을 생성하고 넓이를 구하는 로직을 구현한다고 하자.
아래 처럼 코드를 짜면, 캡슐화를 위반한것이다.
Reactangle 클래스에 넓이를 구현하는 메서드를 작성하여 넓이를 구하는 로직(책임)을 할당해주어야 한다.
public class Reactangle{
private int width;
private int height;
get.. set...
}
public class Calculate{
public static void main(String[] args){
Reactangle rect = new Reactangle();
int 넓이 = rect.getWidth() * rect.getHeight();
}
}
데이터 중심의 설계 (예제:영화예매)
Movie
movie 클래스의 isDiscountable 을 보자
상영시간과 순서를 보며 할인 조건들이 맞는지 확인하고 있다.
public boolean isDiscountable(LocalDateTime whenScreened, int sequence) {
for(DiscountCondition condition : discountConditions) {
if (condition.getType() == DiscountConditionType.PERIOD) {
if (condition.isDiscountable(whenScreened.getDayOfWeek(), whenScreened.toLocalTime())) {
return true;
}
} else {
if (condition.isDiscountable(sequence)) {
return true;
}
}
}
return false;
}
DiscountCondition
isDiscountable 메서드가 매개변수만 달리하여 오버로딩했다.
할인조건에 맞는지 아닌지 파악할 수 있다.
public boolean isDiscountable(DayOfWeek dayOfWeek, LocalTime time) {
if (type != DiscountConditionType.PERIOD) {
throw new IllegalArgumentException();
}
return this.dayOfWeek.equals(dayOfWeek) &&
this.startTime.compareTo(time) <= 0 &&
this.endTime.compareTo(time) >= 0;
}
public boolean isDiscountable(int sequence) {
if (type != DiscountConditionType.SEQUENCE) {
throw new IllegalArgumentException();
}
return this.sequence == sequence;
}
Screen
Screen 클래스의 calculate 메서드이다.
movie 클래스의 할인정책을 판단하고 영화의 할인조건에 따라 할인을 한다.
public Money calculateFee(int audienceCount) {
switch (movie.getMovieType()) {
case AMOUNT_DISCOUNT:
if (movie.isDiscountable(whenScreened, sequence)) {
return movie.calculateAmountDiscountedFee().times(audienceCount);
}
break;
case PERCENT_DISCOUNT:
if (movie.isDiscountable(whenScreened, sequence)) {
return movie.calculatePercentDiscountedFee().times(audienceCount);
}
case NONE_DISCOUNT:
movie.calculateNoneDiscountedFee().times(audienceCount);
}
return movie.calculateNoneDiscountedFee().times(audienceCount);
}
할인금액을 계산하는데, isDiscountable 메서드가 중복되어 사용된다.
movie, DiscoutCondition 클래스에서도 로직이 노출되어있다. 서로 강하게 결합되어있어 할인조건이 추가되면, movie 클래스의 내부 로직을 수정해야한다...
즉, 변경에 취약하다는걸 볼 수 있다.
데이터 중심으로 먼저 생각하지말자!
예를 들어, 영화는 할인 조건이 필요하고.. 제목이 필요하고.. 할인정책이 무엇인지 정해야하고...
책임 기준으로 먼저 생각하자
책임기준으로 설계하는 방법은 5장에 다룬다.
설계방법의 결과는 2장에서 나온 코드이다.
'오브젝트' 카테고리의 다른 글
6장 메세지와 인터페이스 (0) | 2025.01.14 |
---|---|
5장 책임을 할당하기 (0) | 2025.01.07 |
3장 역할, 책임, 협력 (0) | 2024.12.27 |
2장 객체지향 프로그래밍 (1) | 2024.12.13 |