인프런 강의 < 스프링 핵심 원리 - 기본편 > 정리



public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
}
역할과 구현 분리

public class FixDiscountPolicy implements DiscountPolicy {
private int discountFixAmount = 1000;
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return discountFixAmount;
} else {
return 0;
}
}
}
public class RateDiscountPolicy implements DiscountPolicy {
private int discountPercent = 10; //10% 할인
@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return price * discountPercent / 100;
} else {
return 0;
}
}
}
정액 정책을 정률 정책으로 변경해도 테스트가 성공적으로 수행됨.BUT
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); 바꿔야됨
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
OrderServiceImpl 코드를 고쳐야한다.코드 변경 때문에 클라이언트 코드에 영향을 준다 - OCP 위반
public class OrderServiceImpl implements OrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
}
Null pointer 에러 발생public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
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;
}
}
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}

AppConfig는 애플리케이션의 실제 동작에 필요한 구현 객체를 생성한다.
AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해서 주입(연결)해준다.
Impl입장에서는 철저하게 추상화에만 의존한다.
Impl입장에서는 생성자로 어떤 객체가 들어올지 알 수 없다.
관심사 분리가 더 명확해졌다.

AppConfig 객체는 memoryMemberRepository 객체를 생성하고 그 참조값을 memberServiceImpl을 생성하면서 생성자로 전달한다.memberServiceImpl 입장에서 보면 의존관계를 마치 외부에서 주입해주는 것 같다고 해서 DI(Dependency Injection)/의존관계 주입 또는 의존성 주입이라 한다.public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
private MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}

AppConfig 영역을 수정해도 클라이언트 코드에 영향을 주지 않는다.DiscountPolicy 추상화 인터페이스에만 의존한다.AppConfig 의존성 주입으로 해결FixDiscountPolicy를 RateDiscountPolicy로 변경해도 클라이언트 코드를 변경할 필요가 없다.AppConfig를 이용해 역할과 구현을 분리하고 나면 제어의 흐름은 AppConfig가 가져간다.IOC라고 부른다.정적인 클래스 의존 관계와, 실행 시점에 결정되는 동적인 객체 의존 관계를 분리해서 생각해야 한다.
OrderServiceImpl은 MemberRepository와 DiscountPolicy에 의존한다.동적 의존 관계IoC 컨테이너 또는 DI 컨테이너 라 한다.DI 컨테이너는 의존 관계 주입에 초점을 맞춘다.< 자료 출처: 스프링 핵심 원리 - 기본편 >