인프런 김영한 선생님 스프링 핵심 원리 강의를 보고 정리한 내용입니다.
OCP, DIP는 아래 글에 정리해 두었다.
https://yooooooni.tistory.com/36
[SOLID] 좋은 객체지향 설계의 5가지 원칙
단일 책임 원칙 (SRP, single responsibility principle) 한 클래스는 하나의 책임만 가져야 한다. 하나의 책임이라는 것은 모호하다. 클 수 있고, 작을 수 있다. 문맥과 상황에 따라 다르다. 중요한 기준은
yooooooni.tistory.com
회원 도메인 설계의 문제점
이 코드의 설계상 문제점은 무엇일까?
다른 저장소로 변경할 때 OCP 원칙을 잘 준수할까?
DIP를 잘 지키고 있을까?
NO
의존관계가 인터페이스뿐만 아니라 구현까지 모두 의존한다는 문제점이 있다.
새로운 할인 정책 적용과 문제점
- 역할과 구현을 충실하게 분리했다 → OK
- 다형성도 활용하고, 인터페이스와 구현 객체를 분리했다 → OK
- DIP, OCP 같은 객체지향 설계 원칙을 충실히 준수했다. → NO
DIP를 위반하는 부분
주문 서비스 클라이언트(OrderServiceImpl)는 DiscountPolicy 인터페이스에 의존하면서 DIP를 지킨 것 같지만 그렇지 않다.
실제 클래스 의존관계를 분석해 보자.
- 추상(인터페이스)뿐만 아니라, 구현 클래스에도 의존하고 있다.
- 추상 의존 : DiscountPolicy
- 구현 의존 : FixDiscountPolicy, RateDiscountPolicy
OCP를 위반하는 부분
구현에 의존하고 있기 때문에 코드를 변경해야지만 확장할 수 있게 된다. 이 과정에서 OCP를 위반한다.
위 코드는 기능을 확장해서 변경하려고 하면, 클라이언트 코드(OrderServiceImpl)에 영향을 준다.
위 문제점들을 해결하는 방법
누군가가 클라이언트인 OrderServiceImpl에 DiscountPolicy의 구현 객체를 대신 생성하고 주입해주어야 한다.
관심사의 분리 - AppConfig의 등장
- 애플리케이션의 전체 동작 방식을 구성(config)하기 위해, "구현 객체를 생성하고 연결"하는 책임을 가지는 별도의 설정 클래스
- AppConfig는 애플리케이션의 실제 동작에 필요한 "구현 객체를 생성"한다.
- AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를 "생성자를 통해서 주입"해준다.
MemberServiceImpl - 생성자 주입
AppConfig를 통해 MemoryMemberRepository를 주입해주게 되면 MemberServiceImpl에서 구현 클래스에 접근하지 않는다. 클라이언트 코드는 오직 인터페이스에만 의존하게 되면서 DIP를 지킬 수 있다.
MemberRepository와 DiscountPolicy를 필드로 갖는 OrderServiceImpl 역시 철저히 추상화에만 의존하게 구현할 수 있다.
정리
- MemberServiceImpl, OrderServiceImpl의 생성자를 통해서 어떤 구현 객체를 주입할지는 오직 외부(AppConfig)에서 결정된다.
- MemberServiceImpl, OrderServiceImpl은 이제부터 의존관계에 대한 고민은 외부에 맡기고 실행에만 집중하면 된다.
- 객체의 생성과 연결은 AppConfig가 담당한다.
- "관심사의 분리" : 객체를 생성하고 연결하는 역할과 실행하는 역할이 명확히 분리되었다.
이와 같은 방식은 클라이언트 입장에서 보면 의존관계를 마치 외부에서 주입해주는 것 같다고 해서 DI(Dependency Injection), 우리말로 의존성 주입이라고 한다.
'Dev > Spring' 카테고리의 다른 글
[Spring] 정적인 클래스 의존관계 vs. 동적인 객체 인스턴스 의존 관계 (0) | 2023.09.11 |
---|---|
[Spring] AppConfig와 제어의 역전(IoC) (0) | 2023.09.10 |
[Spring] 스프링이란? (0) | 2023.09.03 |
[Spring] DI를 사용하여 구현 클래스 변경하기 (0) | 2023.09.01 |
[Spring] 스프링 빈과 의존관계 (0) | 2023.09.01 |