새로운 할인 정책을 확장해보자
기존에 1000원만 할인 했다면 10%로 정해두면 10000원이면 1000원 20000이면 2000원을 할인해야한다.
RateDiscountPolicy 클래스를 만들자
회원 등급이 VIP면 10%할인해주는 로직이다.
테스트 클래스 만들자. 단축키(shift + ctrl + t)
정책 인터페이스에 RateDiscountPolicy를 할당한다. 그리고 테스트한다.
할인 정책을 변경하려면 클라이언트의 OrderServicImpl 코드를 고쳐야 한다.
우리는 역할과 구현을 충실하게 분리했다.
다형성도 활용하고, 인터페이스와 구현 객체를 분리했다.
OCP, DIP같은 객체지향 설계 원칙을 충실히 준수했다.
=> 그렇게 보이지만 사실은 아니다.
주문 서비스 클라이언트는 DiscountPolicy 인터페이스만 의존하는 것이 아니라 해당 구체 클래스에도 의존하고 있다.
실제 이렇게 의존한다.
DIP 위반한다. 추상화에 의존해야 한다.
정액에서 정률정책으로 변경하는 순간 주문서비스에서도 코드변경이 일어난다. OCP 위반한다.
=> DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경하면 된다.
final은 무조건 값을 할당해야 함 그래서 final 빼고 구현체 클래스 빼고 실행하면 에러가 발생한다. 널 포인트 exception
이 문제를 해결하기 위해선 누군가가 클라이언트의 OrderServicImpl에 DiscountPolicy의 구현 객체를 대신 생성하고 주입해주어야 한다.
AppConfig에서 구현 객체를 생성하고 연결하는 책임을 가진다.
기존에는 new해서 MemoryMemberRepsository를 직접 생성했다. 하지만 지금은 생성자를 통해서 외부에서 주입(DI)받는다.
이로서 인터페이스만 의존하고, 외존관계는 Config에서 설정한다.
기존에 보면 MemoryMemberRepository가 중복되는 것을 볼 수 있다. 하지만 리펙토링 코드에서는 중복제거한 것을 볼 수 있다.
FixDiscountPolicy -> RateDiscountPolicy로 변경
AppConfig로만 변경해서 변경가능
이전에 클라이언트 객체는 직접 구현 객체를 생성하고, 연결하고, 실행하는 책임을 가지고 있었음
구현객체를 생성하고 연결하는 책임은 AppConfig가 담당
클라이언트 객체는 실행하는 책임만 담당
DIP 의존관계 역전 원칙
프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다. 의존성 주입은 이 원칙을 따르는 방법 중 하나이다.
OCP 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
AppConfig가 의존관계를 Fix -> Rate로 변경해서 클라이언트 코드에 주입하므로 클라이언트 코드는 변경하지 않아도 됨
소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있다.