이 포스팅은 인프런 강의 중 김영한님의 '스프링 핵심 원리 - 기본편' 중
섹션 3까지의 내용을 정리한 것입니다.
코드 및 사진 이미지 모두 해당 강의를 참고하였습니다.
스프링 핵심 원리 - 기본편 링크
설계를 하다보면 각종 요구사항을 받게 된다.
요구사항 중 할인 정책 부분에서
- 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
- 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루
고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)
라는 정책이 있다.
이럴 경우, 할인 정책 같은 경우는 지금 결정하기 어렵지만, 정책이 결정될때까지 개발을 무한정 미룰수도 없다.
따라서 이럴 경우 인터페이스를 만들고, 구현체를 갈아끼울 수 있도록 설계하면 된다.
-> 정액 할인정책 객체 다이어그램
-> 정률 할인정책 객체 다이어그램
출처: (인프런) '김영한'
스프링 핵심 원리 - 기본편
위 다이어그램처럼 정액 할인정책 코드와 정률 할인정책 코드를 작성해놓고, 상황에 따라 바꿔 끼우기만 하면 되는 것이다.
할인 정책 인터페이스에서
int discount(Member member, int price);를 만들어
멤버 객체와 가격을 받아와서, 할인 정책에 따라
가격을 반환하도록 메서드의 반환형을 설정한다.
따라서 이 인터페이스에 따라
정액 할인정책에서는 특정한 가격을 뺀 나머지를 반환하도록 하고, 정률 할인정책 클래스에서는 특정한 퍼센트를 뺀 나머지 금액을 반환하도록 설계했다.
그런데 코드 설계 중 문제가 있었다.
OrderService 클래스에서는 멤버를 불러오고, 할인정책을 연결해서 전체적인 주문서비스를 구현했는데
public class OrderServiceImpl implements OrderService {
private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); //고정할인금액.
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); //정률할인금액
이런식으로, Service 클래스에서 코드를 변경하게 될 경우
이는 인터페이스를 의존하는 것 뿐만 아니라, 구현체(클래스)에도 의존하게 된다.
이는 SOLID 원칙 중 OCP원칙을 위반하게 되는 것이다.
->기대했던 의존 관계
출처: (인프런) '김영한'
스프링 핵심 원리 - 기본편
따라서 인터페이스만 의존하도록 의존관계를 변경하였다.
public class OrderServiceImpl implements OrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
}
그러나 구현체를 연결해줘야 하는 문제점이 남았다.
이 부분에서는 AppConfig 클래스를 만들어 해결해주었다.
public class AppConfig {
public OrderService orderService() {
return new OrderServiceImpl(
new MemoryMemberRepository(),
new FixDiscountPolicy());
}
}
AppConfig는 생성한 객체 인스턴스의 참조를 생성자를 통해 주입해주었다. 그런 후 각 클래스에 생성자를 만들어주었다.
클래스 입장에서는 어떤 구현 객체를 주입당할지는 모르고, 이는 AppConfig에 의해서 결정된다. 의존관계는 고민하지 않고 실행에만 집중할 수 있게 된 것이다.
->AppConfig를 통한 생성자 주입 모습.
출처: (인프런) '김영한'
스프링 핵심 원리 - 기본편