저번에 다형성과 구현과 역할을 분리해서 코드를 짰지만, OCP원칙과 DIP원칙을 위반하는 것을 확인했다.
📌 OCP : 개방-폐쇄 원칙
- 변경 시, 기존 코드를 변경하지 않아도 가능 해야한다.
📌 DIP : 의존 관계 역전 원칙
- 추상화에 의존해야한다.
🤔 왜? 구현체에서도 의존하고 있었기 때문
→ private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
⚒️ private final DiscountPolicy discountPolicy;
이를 위한 실제 구현은 어떻게?
📌 관심사를 분리하자
📌 config
📌 할인 정책 변경하기
⬇️ OrderServiceImpl
코드 내용
public class OrderServiceImpl implements hello.core.order.OrderService {
private final hello.core.member.MemberRepository memberRepository;
private final hello.core.discount.DiscountPolicy discountPolicy;
public OrderServiceImpl() { /* compiled code */ }
public hello.core.order.Order createOrder(java.lang.Long memberID, java.lang.String itemName, int itemPrice) { /* compiled code */ }
}
config
) 하기 위해, 구현 객체를 생성하고 연결하는 별도의 설정 클래스를 만들자.📄 Appconfig
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(
new MemoryMemberRepository(),
new FixDiscountPolicy());
}
}
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepsitory()); //참조값을 넣어준다.
}
private static MemberRepository memberRepsitory() {
return new MemoryMemberRepository();
}
public OrderService orderService() {
return new OrderServiceImpl( memberRepsitory(), discountPolicy());
}
private static DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
}
📄 MemberServiceImpl - 생성자 주입
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
👉 MemberServiceImpl
은 이제부터 의존관계에 대한 고민은 외부에 맡기고 실행에만 집중하면 된다.
📄 OrderServiceImpl - 생성자 주입
public class OrderServiceImpl implements OrderService{
//주문을 받은 다음, 회원 조회 , 할인 적용을 해야한다.
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
다른 코드도 마저 수정
MemberAPP
/ OrderApp
/ AppMemberServiceTest
/ OrderServiceTest
에서 사용하는 구현객체를 appConfig
통해 설정한다. public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("find Member = " + findMember.getName());
}
}
클라이언트인 memberServiceImpl
의 의존관계를 외부appConfig
에서 주입해준다.
👉 의존관계를 외부에서 주입
객체를 생성하고 연결하는 역할과 실행하는 역할이 명확히 분리되었다.
📌 추상화에 의존해야한다.
클라이언트인 MemberServiceImpl
은 실제 구현객체를 모르고 역할(인터페이스
)에만 의존한다.
📄 appConfig 코드만 변경
public class AppConfig {
private static DiscountPolicy discountPolicy() {
return new RateDiscountPolicy(); //OCP 원칙 지킴!!
}
}
👉 discountPolicy
의 메서드 코드만 수정
💻 실제 동작
OrderApp
에서 가격을 20000원으로,
public class OrderApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
OrderService orderService = appConfig.orderService();
Long memberID = 1L;
Member memberA = new Member(memberID, "memberA", Grade.VIP);
memberService.join(memberA);
Order order = orderService.createOrder(memberID, "itemA", 20000);
System.out.println("order = " + order);
}
}
👉 10%할인 정책이 적용된것을 확인할 수 있다.
order = Order{memberID=1, itemName='itemA', itemPrice=20000, discountPrice=2000}
📌 개방 폐쇄 원칙
👉 기존 코드를 변경하지 않고, 기능을 확장할 수 있었다.
너무 많은 관심과 역할 : <클라이언트인 주문 서비스 구현체>
- 주문 기능 수행
- 할인 정책도 수행
appConfig를 통해서
1. 실행하는 사용영역과 객체를 생성하고 연결하는 구성부분을 분리했다.
2. 각 코드의 관심사와 역할을 분리하였다.
3. appConfig를 통해 의존관계를 주입하면서
👉 클라이언트는 추상화에 의존하는 DIP를 지키게 되었다.
👉 기능 변경시 기존 코드를 변경하지 않아도 되는 OCP를 지키게 되었다.
👍 너무 많은 관심은 좋지 않아.
→ 관심을 줄여서 "책임을 명확하게"
스프링 조금 재미있을지도?