주문한 금액의 %를 할인해주는 새로운 정률 할인 정책을 추가!
RateDiscountPolicy 코드 추가
package com.example.springex1.discount;
import com.example.springex1.member.Grade;
import com.example.springex1.member.Member;
public class RateDiscountPolicy implements DiscountPolicy{
private int discountPercent = 10;
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return price * discountPercent / 100;
} else {
return 0;
}
}
}
결과
java/com/example/springex1/order/OrderServiceImpl.java
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); --> 아래 코드로 변경
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
문제점
OCP, DIP 같은 객체지향 설계 원칙을 충실히 준수?
- DIP: 주문서비스 클라이언트(OrderServiceImpl)는 추상(인터페이스) 뿐만 아니라 구체(구현) 클래스에도 의존하고
있다.
- 추상(인터페이스) 의존 : DisCountPolicy
- 구체(구현) 클래스 : FixDiscountPolicy, RateDiscountPolicy
- 지금 코드는 기능을 확장해서 변경하면, 클라이언트 코드에 영향을 준다! 따라서 OCP를 위반한다.
실제 의존 관계
정책변경
중요!: 즉 FixDiscountPolicy를 RateDiscountPolicy로 변경하는 순간 OrderServiceImpl의 소스 코드도 함계 변경해야 한다! OCP 위반
어떻게 문제를 해결?
private final MemberRepository memberRepository = new MemoryMemberRepository();
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); --> 아래 코드로 변경
// private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
AppConfig
package com.example.springex1;
import com.example.springex1.discount.FixDiscountPolicy;
import com.example.springex1.member.MemberService;
import com.example.springex1.member.MemberServiceImpl;
import com.example.springex1.member.MemoryMemberRepository;
import com.example.springex1.order.OrderService;
import com.example.springex1.order.OrderServiceImpl;
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(
new MemoryMemberRepository(),
new FixDiscountPolicy());
}
}
참고 : 지금은 각 클래스에 생성자가 없어서 컴파일 오류가 발생한다. 바로 다음에 코드에서 생성자를
만든다.
MemberServiceImpl - 생성자 주입
package com.example.springex1.member;
public class MemberServiceImpl implements MemberService {
// private final MemberRepository memberRepository = new MemoryMemberRepository(); 변경 전 코드
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);
}
}
OrderServiceImpl - 생성자 주입
package com.example.springex1.order;
import com.example.springex1.discount.DiscountPolicy;
import com.example.springex1.discount.FixDiscountPolicy;
import com.example.springex1.discount.RateDiscountPolicy;
import com.example.springex1.member.Member;
import com.example.springex1.member.MemberRepository;
import com.example.springex1.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();
// private DiscountPolicy discountPolicy;
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
클래스 다이어그램
테스트 코드 오류 수정
class MemberServiceTest {
// MemberService memberService = new MemberServiceImpl(memberRepository);
MemberService memberService;
@BeforeEach
public void beforeEach() {
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
}
class OrderServiceTest {
// MemberService memberService = new MemberServiceImpl(memberRepository);
// OrderService orderService = new OrderServiceImpl();
MemberService memberService;
OrderService orderService;
@BeforeEach
public void beforeEach() {
AppConfig appConfig = new AppConfig();
memberService = appConfig.memberService();
orderService = appConfig.orderService();
}
결과
참고
김영한: 스프링 핵심 원리 - 기본편(인프런)
Github - https://github.com/b2b2004/Spring_ex