김영한 강사님 강의를 들으며 공부한 내용 입니다.
- 악덕 기획자 : 서비스 할인 정책을 고정 금액 할인 에서 정률% 할인 정책으로 바꾸고 싶다. 예를들어 10%로 지정해두면 고객이 10000원 주문시 1000원 할인, 20000원 주문시 2000원 할인이다.
할인 정책을 변경하려면 클라이언트인 OrderServiceImpl을 고쳐야 한다.
public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
OCP, DIP 같은 객체지향 설계 원칙을 충실히 지킨것 같지만 그게 아니다.
DIP : 주문서비스 클라이언트(OrderServiceImpl)는 DiscountPolicy 인터페이스에 의존하면서 DIP를 지킨 것 같은데?
-> 클래스 의존관계를 보면 추상(인터페이스) 뿐만 아니라 구체(구현) 클래스에도 의존하고 있다.
->추상(인터페이스) 의존 : DiscountPolicy
->구체(구현)클레스 : FixDiscountPolicy, RateDiscountPolicy
OCP : 변경하지 않고 확장할 수 있는가?
-> 앞의 코드는 기능을 확장해서 변경하면, 클라이언트 코드에 영향을 주기 때문에 OCP를 위반한다.



실제 의존관계를 보면 클라이언트인 OrderServiceImpl이 DiscountPolicy 인터페이스 뿐만 아니라 FixDiscountPolicy인 구체 클래스도 함께 의존하고 있다.
->DIP위반


그래서 FixDiscountPolicy를 RateDiscountPolicy로 변경하는 순간 OrderServiceImpl의 소스코드도 함께 변경해야 한다.
-> OCP 위반
인터페이스에만 의존하도록 코드 변경
public class OrderServiceImpl implements OrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
}
->해결방안
애플리케이션의 전체 동작 방식을 구성하기 위해, 구현 객체를 생성하고, 연결하는 책임을 가지는 별도의 설정 클래스를 만들자.
AppConfig는 애플리케이션의 실제 동작에 필요한 구현 객체를 생성한다.
-> MemberServiceImple
-> MemoryMemberRepository
-> OrderServiceImpl
-> FixDiscountPolicy
MemberServiceImpl - 생성자 주입
package hello.core.member;
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
public void join(Member member) {
memberRepository.save(member);
}
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}



appConfig는 memberService 객체를 만들 때 memoryMemberRepository도 생성한다. 그 다음 memberServiceImpl를 생성할 때 memoryMemberRepository의 참조값 "X001"을 같이 생성자에 넘긴다. -> memberServiceImpl은 생성한 memoryMemberRepository의 값을 주입받게 된다.


