OrderServiceImpl
코드 수정 public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
OrderServiceImpl
의 코드를 변경해야한다.DiscountPolicy
FixDiscountPolicy
, RateDiscountPolicy
OrderServiceImpl
(생성자 주입) public class OrderServiceImpl implements OrderService{
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(DiscountPolicy discountPolicy){
this.discountPolicy = discountPolicy;
}
}
RateDiscountPolicy
)에 의존하지 않게되고, 인터페이스에만 의존한다.OrderServiceImpl
생성자를 통해서 어떤 구현 객체가 주입될지는 AppConfig
에서 결정한다.AppConfig
를 통해서 관심사를 확실하게 분리했다.AppConfig
는 애플리케이션의 전체 구성(의존 관계 등)을 책임진다.AppConfig
)만 영향을 받고, 사용 영역은 영향을 받지 않는다.AppConfig
)public class AppConfig {
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
App Config
)를 통해 클라이언트 객체(OrderServiceImpl
)는 실행하는 책임만 담당한다.App Config
가 담당AppConfig
를 통해 OrderServiceImpl
에서 추상화(인터페이스)에만 의존하게 코드를 수정했다.AppConfig
를 통해 OrderServiceImpl
에서 다른 할인 정책으로 바꿀 때 코드를 변경할 필요가 없다.AppConfig
등장 전
OrderServiceImpl
가 스스로 필요한 구현 객체를 생성하고, 연결하고 실행했다.OrderServiceImpl
가 제어 흐름을 스스로 조종했다.AppConfig
등장 후
OrderServiceImpl
은 자신의 로직을 수행하는 역할만 담당한다.AppConfig
가 가지고 있다.IoC: 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부(AppConfig)에서 관리하는 것
프레임워크 vs 라이브러리
public OrderService orderService(){
return new OrderServiceImpl(new RateDiscountPolicy());
}
AppConfig
)에서 실제 구현 객체를 생성하고 클라이언트에 AppConfig
처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것SpringConfig
: 스프링을 통한 DI 적용@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
@Configuration
: SpringConfig에 설정을 구성한다.@Bean
: 스프링 컨테이너에 스프링 빈으로 등록된다.public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
long memberId = 1L;
Member member = new Member(memberId, "memberA", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "itemA", 10000);
System.out.println("order = " + order);
}
ApplicationContext
: 스프링 컨테이너
@Configuration
이 붙은 SpringConfig
를 설정 정보로 사용@Bean
이 붙은 모든 메서드를 호출applicationContext.getBean()
applicationContext.getBean("memberService", MemberService.class)
"memberService"
: 필요한 스프링 빈 이름(해당 객체를 반환하는 메서드 이름는MemberService.class
: 타입AppConfig
)로 의존관계를 설정해줬지만, 스프링을 이용하여(SpringConfig
)스프링 컨테이너에 객체를 스프링 빈으로 등록하고, 스프링 컨테이너에서 스프링 빈을 찾아서 사용하도록 변경했다.