스터디/스프링 핵심 원리 - 기본편
스프링 핵심 원리 이해2 - 객체 지향 원리 적용 [새로운 할인 정책]
멩주
2022. 9. 11. 02:38
애자일 소프트웨어 개발 선언
공정과 도구보다 개인과의 상호작용
포괄적인 문서보다 작동하는 소프트웨어를
계약 협상보다 고객과의 협력을
계획을 따르기보다 변화에 대응하기를
새로운 할인 정책 개발
RateDiscountPolicy
public class RateDiscountPolicy implements DisvountPolicy{
private int discountPercent = 10;
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP){
return price * discountPercent / 100;
}
return 0;
}
}
RateDiscountPolicyTest
class RateDiscountPolicyTest {
RateDiscountPolicy discountPolicy = new RateDiscountPolicy();
@Test
@DisplayName("VIP는 10% 할인이 적용되어야 한다")
void vip_o(){
//given
Member member = new Member(1L, "memberVIP", Grade.VIP);
//when
int discount = discountPolicy.discount(member, 10000);
//then
Assertions.assertThat(discount).isEqualTo(1000);
}
@Test
@DisplayName("VIP가 아니면 할인이 적용되지 않아야 한다.")
void vip_x(){
//given
Member member = new Member(1L, "memberBASIC", Grade.BASIC);
//when
int discount = discountPolicy.discount(member, 10000);
//then
Assertions.assertThat(discount).isEqualTo(0);
}
}
test의 경우 실패값도 확인해야 한다.
새로운 할인 정책 적용과 문제점
실제 새로운 할인 정책을 적용하기 위해서 클라이언트인 OrderServiceImpl을 수정해야 한다.
public class OrderServiceImpl implements OrderService{
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
문제점
역할과 구현 분리다형성 활용, 인터페이스와 구현 객체 분리- OCP, DIP 같은 객체 지향 설계 원칙 준수?
- DIP: 주문 클라이언트인 OrderServiceImpl은 DiscountPolicy 인터페이스에 의존하면서 DIP를 지킨거 아니야?
- 클래스 의존관계를 살펴보면 인터페이스 뿐만 아니라 구현 객체(클래스, Fixed or RateDiscountPolicy)에 의존하고 있다.
- 인터페이스: DiscountPolicy/ 구현 클래스: Fixe or RateDiscountPolicy
- OCP: 변경하지 않고 확장할 수 있다는데?
- 클라이언트인 OrderServiceImpl의 수정이 일어났다!
클라이언트인 OrderServiceImpl이 DiscountPolicy 인터페이스 뿐만 아니라 FixDiscountPolicy인 구체 클래스도 함께 의존하고 있다. new를 통해서!
DIP 위반!
또한 이로 인해 OrderServiceImpl 즉 클라이언트의 코드가 변경된다.
OCP 위반!
이 문제를 어떻게 해결할 수 있을까?
- 클라이언트 코드인 OrderServiceImpl은 DiscountPolicy의 인터페이스 뿐만 아니라 구현 클래스도 함께 의존한다.
- 그래서 구체 클래스를 변경 시, 클라이언트 코드도 함께 변경된다.
- DIP 위반 -> 추상에만 의존하도록 변경
- DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경하면 된다.
public class OrderServiceImpl implements OrderService{
private DiscountPolicy discountPolicy;
}
final은 값이 무조건 할당되어야 한다.
- 인터페이스에만 의존하도록 설계 코드 변경
- 그런데 구현체가 없는데 어떻게 코드를 실행할 수 있을까? <- NullPointerException
클라이언트인 OrderServiceImpl에 DiscountPolicy의 구현 객체를 대신 생성하고 주입하자!