[아이템 64] 객체는 인터페이스를 사용하라
Closed this issue · 4 comments
- 읽다보니까, Spring DI (Dependency Injection) 이 생각나는 것 같네요..
- https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring
- 읽다보니까, Spring DI (Dependency Injection) 이 생각나는 것 같네요..
- https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring
저도 이거 보면서 DI 만 생각났네요.. 근데 확실히 인터페이스를 잘 쓰면 프로그램이 상당히 유연해지고, 코드를 짜는 습관에도 도움이 많이 되더라고요. 먼져 추상화 시키려하는 습관들이 생겨서
제가 Spring 을 전혀 몰라서, 덕분에 올려주신 링크 읽어보면서 공부를 할 수 있었는데,
"객체는 인터페이스를 사용해라" 에서 DI 가 떠오르신 이유가 무엇인지 좀더 설명해주실 수 있으신가요?
보니깐 ApplicationContext 에서 xml 에 정의된 내용에 따라,
클래스의 인터페이스로 선언된 객체에게 실제 클래스를 "Injecting" 하는 내용 같은데,
DI 를 하기 위해서는 인터페이스를 사용해야하기에 떠오르셨던건가요?
대화 흐름을 못따라가서 여쭈어봅니다.
토비의 스프링, 김영한님의 스프링 강의를 수강하면서 정리한 내용입니다.
제어의 역전 (IoC: Inversion of Control)
- AppConfig가 등장 후 구현 객체는 자신의 로직을 실행하는 역할만 한다. 프로그램의 제어 흐름은 AppConfig가 담당한다.
→ orderServiceImpl은 필요한 인터페이스들을 호출하지만 어떤 구현 객체들이 실행될지 모름. - 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것
→ 제어의 역전(IoC)
프레임워크 vs 라이브러리
- 프레임워크: 내가 작성한 코드를 제어, 대신 실행하면 프레임워크(JUnit)
- 라이브러리: 내가 작성한 코드가 직접 제의 흐름을 담당. (객체 → JSON으로 바꾸기)
의존관계 주입(DI: Dependency Injection)
- 인터페이스에 의존하기 때문에 실제 어떤 구현 객체가 사용될지는 모른다.
- 의존관계는 정적인 클래스 의존 관계와 실행 시점에 결정되는 동적인 객체(인스턴스) 의존 관계 둘을 분리해서 생각해야 한다.
정적인 클래스 의존 관계
import 코드만 보고 의존관계를 쉽게 판단할 수 있다.
→ 정적인 의존관계는 애플리케이션을 실행하지 않아도 분석할 수 있다.
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();
}
}
// OrderServiceImpl.class
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;
}
}
이제 여기서 OrderSeviceImpl에서 고정 할인 정책이 아닌 할인율 정책으로 변경할 경우
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
로만 바꾸면 됩니다. 서비스 로직인 OrderServiceImpl에서 바꿀 필요가 없겠죠? 이건 자바로직이고 여기서 만약 스프링으로 전환한다면
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
로 애너테이션으로 등록이 가능합니다. 김영한님 강의에서는 xml에서 애너테이션으로 바꾸는 추세라고 하셨고, xml을 쓴다고 하면 아마 레거시쪽이 많이 쓸 듯하네요.
IoC는 제어의 역전이며, DI는 스프링 프레임워크에서 지원하는 IoC의 형태라고 생각하시면 됩니다. 자세한건
인프런의 김영한님 강의 또는 토비의 스프링을 추천합니다!!