정액 할인 정책을 정률로 바꾸었을 때 클라이언트에 영향을 주지 않는지 역할이 잘 분리되었는지 확인 해볼 예정임
객체 지향 원리 적용
✔︎ 새로운 할인 정책 개발
core.discount.DiscountPolicy
package hello.core.discount;
import hello.core.member.Member;
public interface DiscountPolicy {
// @return 할인 대상 금액
int discount(Member member, int price);
}
core.discount.FixDiscountPolicy
package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
public class FixDiscountPolicy implements DiscountPolicy{
private int discountFixAmount = 1000; //1000원 할인
//VIP일경우 1000원 할인 아니면 할인x
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP){
return discountFixAmount;
} else {
return 0;
}
}
}
core.discount.RateDiscountPolicy
package hello.core.discount;
import hello.core.member.Grade;
import hello.core.member.Member;
public class RateDiscountPolicy implements DiscountPolicy{
private int discountPercent = 10;
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP){ //멤버등급이 vip일 경우
return price * discountPercent / 100;
} else {
return 0;
}
}
}
✔︎ 새로운 할인 정책 적용과 문제점
- 적용시키기 위해서는 order.OrderServiceImpl 에서 적용시켜야함
order.OrderServiceImpl
- FixDiscountPolicy를 RateDiscountPolicy로 바꿔주어야 함
package hello.core.order;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberrepository;
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberrepository();
//private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
//member 찾음
Member member = memberRepository.findById(memberId);
//단일책임의 원칙 잘 지켜짐 할인정책에 문제가 있을때 할인정책만 수정 가능
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
- 할인정책을 변경하기 위해서는 클라이언트인 OrderServiceImpl
단순히 DiscountPolicy에만 의존을 하고 있다고 알고 있었지만
OrderServiceImpl에서는 DiscountPolicy 뿐만 아니라 FixDiscountPolicy인 구체 클래스도 함께 의존하고 있다. → DIP 위반
#DIP(Dependency Inversion Principle) : 저수준 모듈이 고수준 모듈에 의존하게 되는 것
AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해서 주입(연결)해준다.
- 설계 변경으로 `MemberServiceImpl` 은 `MemoryMemberRepository` 를 의존하지 않는다! 단지 `MemberRepository` 인터페이스만 의존한다.
- MemberServiceImpl` 입장에서 생성자를 통해 어떤 구현 객체가 들어올지(주입될지)는 알 수 없다.
- MemberServiceImpl` 의 생성자를 통해서 어떤 구현 객체를 주입할지는 오직 외부( `AppConfig` )에서 결정된 다.
- MemberServiceImpl` 은 이제부터 **의존관계에 대한 고민은 외부**에 맡기고 **실행에만 집중**하면 된다.
core.MemberServiceImpl 기존의 이코드에서
package hello.core.member;
//회원 서비스 구현체
public class MemberServiceImpl implements MemberService{
//가입하고 찾으려면 memory레포가 있어야함 구현객체를 MemoryMemberRepository로 선택
private final MemberRepository memberRepository = new MemoryMemberrepository(); //2. 여기서 할당이 됨
//join에서 save를 호출하면 다형성에 의해서 Memory레포에 있는 save(오버라이드한개)가 호출됨
public MemberServiceImpl(MemberRepository memberRepository){ //1. 여기서 memorymemberReposiotry가 들어와서
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
이걸로 변경
package hello.core.member;
//회원 서비스 구현체
public class MemberServiceImpl implements MemberService{
//가입하고 찾으려면 memory레포가 있어야함 구현객체를 MemoryMemberRepository로 선택
private final MemberRepository memberRepository;
//join에서 save를 호출하면 다형성에 의해서 Memory레포에 있는 save(오버라이드한개)가 호출됨
public MemberServiceImpl(MemberRepository memberRepository){ //1. 여기서 memorymemberReposiotry가 들어와서
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}