📣 참고 : 애자일 소프트웨어 개발 선언
RateDiscountPolicy
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
// ↑ 변경 전
// OCP 위반! - 결국 코드를 변경해야 하기 때문
// DIP 위반! - 추상(인터페이스)에만 의존해야 하는데 구현(클래스)에도 의존하고 있기 때문
// 그러면 이렇게 바꾸면?
private DiscountPolicy discountPolicy;
// => 당연히 NPE 발생!
...
}
}
애플리케이션의 전체 동작 방식을 구성(config)하기 위해, 구현 객체를 생성하고 연결하는 책임을 가지는 별도의 설정 클래스를 만들자.
애플리케이션의 실제 동작에 필요한 "구현 객체를 생성"한다.
생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해 주입(연결)한다.
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;
}
@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);
}
}
MemberServiceImpl
입장에서 이제는 생성자를 통해 어떤 구현 객체가 들어올지는 알 수 없다.AppConfig
)에서 결정한다.memberServiceImpl
입장에서 보면, 의존관계를 마치 외부에서 주입해주는 것 같다고 해서 DI(Dependency Injection), 우리 말로 의존관계 주입 또는 의존성 주입이라고 한다.변경 후
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
private MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}