Spring 핵심 원리 기본편 (3) - SOLID 관점에서 바라 본 DI / DI, IoC, DI 컨테이너
소개
- 이번 글은 순수 Java를 활용한 코드임 (Spring사용 X)
- DI와 DI컨테이너가 어떤 역할을 할 수 있는지가 핵심
- 회원이 주문을 하는 간단한 예제로 코드를 변경할 예정
- SOLID 5가지 관점에서 DI의 적용 전/후를 비교해서 보는것이 중요
비즈니스 요구사항
member
의 회원가입 / 조회
member
는 BASIC
/ VIP
등급이 존재
member
는 상품을 주문할 수 있음
VIP member
는 상품 할인이 적용 (할인 방식 미정)
- 고정(Fix) 금액 할인
- 일정(Rate) 비율 할인
다이어 그램
[ member ]
- 주의할 점은 DB가 아직 정해지지 않은 상황이다
MemberRepository
는 단순 메모리를 사용하는 MemoryMemberRepository
나 DB를 사용하는 DBMemberRepository
로 대체될 수 있다
[ Order & Discount ]
- 할인 정책(Discount Policy)은 미정상태라서 대체될 수 있는 환경이다.
- 우리는 최초에 할인 정책을 변경할 때 발생되는 DIP/OCP문제에 집중해야 한다
DI적용 전
(OrderServiceImpl.java)
- 상단 코드에서는 할인 정책이 바뀔 때 마다 Client Code인
OrderServiceImpl
을 변경해야 하는 문제점이 발생한다.
- DIP 위배
: 인터페이스 뿐만 아니라 직접적인 구현체까지 의존하고 있기 때문
- OCP 위배
: 기능을 확장하면 (할인정책을 바꾸면) Client Code를 직접 수정해야 함
(MemberServiceImpl.java)
- 기능이 확장(DB가 변경)될 때
MemberServiceImpl
코드는 수정된다
- OCP위배
: DB가 변경된다면 memberRepository 생성하는 new뒤에를 직접 변경해야함
- DIP 위배
: 인터페이스를 의존하지만, 구현체 역시 의존
DI적용 후
(AppConfig.java) 작성
- DI를 적용하기 전 코드는 마치 영화배우가 직접 다른 영화배우를 캐스팅 하는 것과 같은 상황이었다
- 객체를 생성하고 관계를 관리하는
공연 관리자
의 역할을 해줌으로써 배우는 어떤 상대 배우가 오든지 자신의 역할만 하면 되게 할 수 있다
- 구현체가 아닌 인터페이스만 바라보게 한 뒤, 실제 사용되는 구현체는 생성자를 통해 의존성을 주입해주는 것!
(OrderServiceImpl.java)
- 객체 간 의존성을
AppConfig.java
에서 관리하기 때문에 interface만 생성 후 생성자를 통해 의존성을 받는 방식
- DIP 지켜짐
: 구현체가 아닌 인터페이스만 의존하는 관계로 변경됨
- OCP 지켜짐
: 기능이 확장되어도 실제 Client Code는 변경되지 않는다!
(AppConfig
만 변경)
(MemberServiceImpl.java)
- 이제 DB가 변경되어도 이 코드들은 변경되지 않아도 된다!
--> AppConfig.java
만 변경되면 된다!
정리
- 구현 객체를 생성하고 연결하는 별도의 클래스(AppConfig)를 생성해서 객체 간 의존성을 관리하여 OCP / DIP 위배 문제를 해결
- 해당 코드는 순수 Java를 사용했지만, DI의 필요성을
SOLID
5가지 관점에서 살펴볼 수 있는 예제
- 애플리케이션 실행시점에 외부에서 실제 구현 객체를 생성해서 실제 의존관계가 연결 되는 것을
의존관계 주입
이라고 함
- DI(의존관계 주입)을 해주는 역할을
DI 컨테이너
라고 함
IoC / DI / DI 컨테이너
- IoC (Inversion of Control)
- 제어의 역전
- 프로그램의 제어 흐름을 개발자가 아닌 프레임워크에게 넘겨 작업의 구현과 수행을 분리할 수 있는 하나의 전략
- 오늘 예제에서는
AppConfig
가 제어의 흐름을 가지고 있다!
- 라이브러리는 IoC를 가능하게 할 수 없다
- DI (Dependency Injection)
- 의존관계 주입
- 정적 클래스 의존관계 / 동적 클래스 의존관계로 분리 가능
- 정적 클래스 의존관계
: 코드만 보고 파악 가능한 의존관계
- 동적 클래스 의존관계
: 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계
- DI 컨테이너 (DI Container)
* DI를 관리하는 컨테이너