-> 공연(애플리케이션)에서 실제 배역에 맞는 배우(인터페이스)를 선택하는 것은 누구인가?
--> 로미오 역할을 누가할지는 배우가 정하는 것이 아니다.
--> 이전 코드는 로미오 역할(인터페이스)를 하는 디카프리오 배우(구현체)가 줄리엣역할(인터페이스)를 하는 여자주인공(구현체)를 직접 초빙하고 있음
---> 즉 디카프리오(구현체)가 공연,주인공초빙 등 "다양한 책임" 가지고 있음
-> 배우(구현체)는 본인의 역할 배역 수행에만 집중해야 함.
--> 공연을 구성하고, 담당 배우를 섭외하고, 역할에 맞는 배우를 지정하는 책임을 담당하는 "공연 기획자"가 필요하다.
--->공연 기획자를 만들고, 배우와 공연 기획자의 책임을 확실히 분리하자
package springbasic.core;
import springbasic.core.discount.FixDiscountPolicy;
import springbasic.core.member.MemberService;
import springbasic.core.member.MemberServiceImpl;
import springbasic.core.member.MemoryMemberRepository;
import springbasic.core.order.OrderService;
import springbasic.core.order.OrderServiceImpl;
public class AppConfig {
//생성자주입
public MemberService memberService(){
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService(){
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
MemberServiceImpl.java - 생성자 주입
-> 더이상 MemberServiceImpl은 MemoryMemberRepository(구현체)에 의존 하지 않는다.
--> 오직 MemberRepository에만 의존한다.
--> MemberServiceImpl 입장에서 생성자를 통해 어떤 구현 객체가 들어올지(주입될 지) 알수 없음
--> MemberServiceImpl의 생성자를 통해서 어떤 구현객체를 주입할 지는 AppConfig에서 결정
--> MemberServiceImpl은 의존관계에 대한 고민은 AppConfig에 맡기고 실행에만 집중함.
의존성 주입!! " 외부에서 의존관계를 주입해주는것과 같음"
OrderServiceImpl.java - 생성자 주입
-> 더이상 OrderServiceImpl FixDiscountPolicy(구현체)에 의존 하지 않는다.
--> 오직 DiscountRepository에만 의존한다.
--> OrderServiceImpl 입장에서 생성자를 통해 어떤 구현 객체가 들어올지(주입될 지) 알수 없음
--> OrderServiceImpl 생성자를 통해서 어떤 구현객체를 주입할 지는 AppConfig에서 결정
--> OrderServiceImpl 의존관계에 대한 고민은 AppConfig에 맡기고 실행에만 집중함.
리펙토링 전 AppConfig.java
리펙토링 후 AppConfig.java
- AppConfig에서 할인정책역할을 담당하는 구현부를 Fix -> Rate 객체로 변경함
- 이제 할인정책 변경 시, 애플리케이션 구성 역할을 담당하는 AppConfig만 변경하면 됨.
-> OrderServiceImpl 등 사용영역의 어떤 코드도 변경할 필요 없음- 구성영역(AppConfig)는 당연히 변경됨.
**
1. SRP 단일책임 원칙 : 한 클래스는 하나의 책임만 가져야 한다.
- 클라이언트 객체(MemberServiceImpl, OrderServiceImpl)는 직접 구현 객체를 생성하고, 연결하고, 실행하는 다양한 책임을 가지고 있었다.
- SRP 단일 책임 원칙에 의해 관심사를 분리함.
- 구현 객체(AppConfig)를 생성하고 연결하는 책임을 담당함.
- 클라이언트 객체(MemberServiceImpl, OrderServiceImpl)는 실행하는 책임만 담당
2. DIP 의존관계 역전 원칙: 프로그래머는 " 추상화에 의존해하고 구체화에 의존하면 안됨", 의존성 주입은 이 원칙을 따르는 방법 중 하나이다
- 새로운 할인 정책을 개발하고, 적용하려고 하니 크라이언트 코드도 변경해야했음.
-> 클라이언트(OrderServiceImpl)가 추상(DiscountPolicy)과 구현체(FixDiscountPolicy) 모두에 의존하고있었기 떄문.- 클라이언트 코드가 추상(DisCountPolicy)에만 의존하도록 변경
- AppConfig에서 객체 인스턴스(FixDiscountPolicy)를 대신 생성하여 클라이언트 코드에 의존관계를 주입해줌
3. OCP : 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
- 다형성 사용하고 클라이언트가 DIP 지킴
- 애플리케이션을 사용 영역과 구성 영역으로 나눔
- 구성영역(AppConfig)에서 의존관계(Fix->Rate)를 변경하여 클라이언트에 주입하므로, 클라이언트 코드는 변경하지 않아도 됨.
- 소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있음