OCP, DIP 원칙을 지키기 위한 방법
그림과 같이 SRP(단일 책임), LSP(리스코프), ISP(인터페이스 분리)를 준수하는 코드가 있다고 가정하자.
OrderServiceImpl
은 DiscountPolicy
인터페이스에 의존하는 것처럼 보이지만 동시에 구현 클래스인 FixDiscountPolicy
와 RateDiscountPolicy
에도 의존하고 있으므로 DIP를 위반하고 있다.FixDiscountPolicy를
RateDiscountPolicy
로 변경하려고 하면 OrderServiceImpl
클라이언트 코드를 직접 변경해야 하므로 OCP를 위반하고 있다.
OCP와 DIP 객체 지향 설계 원칙을 준수하도록 만들기 위해서는 인터페이스에만 의존하도록 변경하면 된다.
설정 클래스(AppConfig) - 객체의 생성과 연결 담당
인터페이스에만 의존하게 하기 위해서는 별도의 설정 클래스(AppConfig
)를 만들어서 구현 객체를 생성하고, 연결(의존성 주입)을 하도록 설정하면 된다. 이를 관심사의 분리라고 한다.
- 구현 객체 생성
MemberServiceImpl
MemoryMemberRepository
OrderServiceImpl
FixDiscountPolicy
- 생성자를 통한 의존성 주입(연결)
MemberServiceImpl
→MemoryMemberRepository
OrderServiceImpl
→MemoryMemberRepository
, `FixDiscountPolicy
설정 클래스(AppConfig
)를 이용하면 인터페이스에만 의존하도록 할 수 있다.
MemberServiceImpl
와OrderServiceImpl
입장에서는 생성자를 통해 어떤 구현 객체가 들어오는지 알 수 없고 자신의 기능에만 집중할 수 있게 된다.
요약 정리
기존의 코드는 구체 클래스에서 구체 클래스에 직접 의존했다. 때문에 DIP를 위반하게 되고 의존하는 클래스를 바꿀 때 클라이언트 코드를 변경해야 하므로 OCP를 위반한다.
이를 해결하기 위해 인스턴스 생성과 의존성 주입을 담당하는 설정 클래스(AppConfig)를 만들었다.
설정 클래스(AppConfig
)가 인스턴스 생성과 의존성 주입을 모두 담당하게 된다.
따라서 의존하는 인스턴스가 바뀌더라도 구현 클래스(MemberServiceImpl
, OrderServiceImpl
)가 아닌 AppConfig
클래스에서 변경하므로 OCP를 지킬 수 있고 인터페이스에 의존하게 되어서 DIP를 지킬 수 있게 된다.
IoC, DI, 그리고 컨테이너
제어의 역전 IoC(Inversion of Control)
전통적인 프로그래밍에서는 개발자가 직접 프로그램의 흐름과 제어를 다루는 반면 IoC는 프레임워크가 객체의 생성, 관리, 제어 흐름을 담당하도록 하는 개념이다.
예를 들면 위에서 설명한 기존의 프로그램은 구현 객체가 필요한 객체 생성과 의존성 주입을 직접 했다. 하지만 객체 생성과 의존성 주입을 설정 클래스(AppConfig
)가 담당하고록 바꾸고 구현 객체는 자신의 로직을 실행하는 역할만 담당하도록 바꾸었다. 이렇듯 프로그램의 제어 흐름을 내부(구현 클래스)에서 직접 제어하는 것이 아닌 외부(설정 클래스)에서 관리하는 것을 제어의 역전(IoC)이라 한다.
의존 관계 주입 DI(Dependency Injection)
객체 간의 의존성을 프레임워크가 주입하는 개념이다.
즉, 객체가 의존하는 객체를 직접 생성하거나 참조하는 대신 외부에서 객체를 생성하고 참조하도록 하는 방식이다.
위에서 설명한 AppConfig
가 하는 역할이 DI이다.
IoC 컨테이너, DI 컨테이너
AppConfig
처럼 객체를 생성하고 의존 관계를 연결해주는 것을 IoC 컨테이너 또는 DI 컨테이너라고 한다.
최근엔 의존 관계 주입에 초점을 맞춰서 주로 DI 컨테이너라고 한다.
다음엔 Spring 프레임워크를 사용하여 DI를 설정해보도록 하겠다.
'Back-end > Spring' 카테고리의 다른 글
[스프링 핵심 원리] 객체 지향 원칙(SOILD) 적용 - 설정 클래스(AppConfig) 사용 (0) | 2024.12.03 |
---|---|
[Spring] 컴포넌트 스캔과 의존 관계 자동 주입 (@ComponentScan, @Autowired) (0) | 2024.09.29 |
[Spring] 싱글톤 패턴과 싱글톤 컨테이너 (1) | 2024.09.25 |
[Spring] 스프링 컨테이너와 스프링 빈(BeanFactory, ApplicationContext) (1) | 2024.09.13 |
실전! 스프링 부트와 JPA 활용1 - 섹션 2. 도메인 분석 설계 (0) | 2023.10.10 |