티스토리 뷰
기획자의 요구 : 고정 할인 금액 정책(FixDiscountPolicy) -> 비율 할인 정책(RateDiscountPolicy)으로 변경해주세요.
public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
위의 코드처럼 FixDiscountPolicy() -> RateDiscountPolicy()로 변경
다형성 : 역할과 구현 분리 (O)
DIP : 클라이언트가 DiscountPolicy 추상 클래스뿐만 아니라 FixDiscountPolicy나 RateDiscountPolicy 구현 클래스에 의존 - DIP 위반
OCP : FixDiscountPolicy에서 RateDiscountPolicy로 바꾸면 클라이언트 코드에 영향을 준다 - OCP 위반
아래 다이어그램과 같이 DIP 위반하지 않도록 인터페이스에만 의존하도록 바꾼다.
public class OrderServiceImpl implements OrderService {
private final DiscountPolicy discountPolicy;
}
인터페이스에만 의존하도록 위의 코드로 바꾸었다.
근데 문제는 구현체가 RateDiscountPolicy인지 FixDiscountPolicy가 없어서 NullPointerException이 발생한다.
관심사의 분리
Appconfig의 등장
애플리케이션의 전체 동작 방식을 설정(config)하기 위해, 구현 객체 생성하고, 연결하는 책임을 가지는 클래스 생성
아래 코드는 중복 제거 리팩토링 후에 AppConfig 코드이다.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public DiscountPolicy discountPolicy() {
//return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
AppConfig의 등장으로 애플리케이션이 크게 사용 영역과, 객체를 생성하고 구성하는영역으로 분리한다.
위의 그림처럼 구성되면 FixDiscountPolicy에서 RateDiscountPolicy로 바꾸어도 구성 영역만 변경되고, 사용 영역은 전혀 영향받지 않는다
IoC, DI, 그리고 컨테이너
제어의 역전(Inversion of Control)
- 기존 프로그램은 클라이언트 구현 개체가 스스로 필요한 서버 객체 구현 생성, 연결, 실행
- 구현 객체가 프로그램의 제어 흐름을 조종
- AppConfig가 등장하여 구현 객체는 자신의 로직을 실행하는 역할만 담당, 프로그램의 제어 흐름은 AppConfig가 가져간다.
- 프로그램의 제어 흐름을 직접 제어하는 것이 아닌 외부에서 관리하는 것을 IoC(Inversion of Control)이라고 한다.
의존관계 주입(Dependency Injection)
- 의존관계는 정적인 클래스 의존관계와, 실행 시점에 결정되는 동적인 객체(인스턴스) 의존관계 둘로 분리
정적인 클래스 의존관계 주입
- 정적인 의존관계는 import코드만 보고 판단 가능
- 애플리케이션을 실행시키지 않아도 분석 가능
동적인 객체 인스턴스 의존관계 주입
- 애플리케이션 실행 시점 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계
- 실행 시점에 외부에서 실제 구현 객체 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계 주입
IoC 컨테이너, DI 컨테이너
- AppConfig 처럼 객체 생성하고 관리하고 의존관계를 연결해주는 것을 IoC 컨테이너, DI 컨테이너라고 한다
스프링으로 전환하기
@Configuration
public class AppConfig {
@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 FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
@Configuration : AppConfig에 설정을 구성
@Bean : 각 메서드 앞에 붙여준다. 스프링 컨테이너에 스프링 빈으로 등록
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
스프링 컨테이너
- ApplicationContext를 스프링 컨테이너라고 부른다.
- 스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성) 정보로 사용
- @Bean이라 적힌 메소드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록 = 스프링 빈
- AppConfig을 통해서 직접 조회했지만, 스프링 컨테이너를 통해서 필요한 스프링 빈 조회 (applicationContext.getBean();)
출처: 스프링 핵심 기본 원리편
'Back-end Programming > Spring' 카테고리의 다른 글
의존관계 자동 주입 (DI: Dependency Injection) (0) | 2021.04.11 |
---|---|
컴포넌트 스캔 (Component Scan) (0) | 2021.04.10 |
싱글톤 컨테이너 (Singleton Container) (0) | 2021.04.09 |
요구 사항에 맞게 예제 코드 만들기 (0) | 2021.04.07 |
객체 지향 설계(OOP)와 스프링(Spring) (0) | 2021.04.06 |