이전 게시글에 이어서 OCP와 DIP에 대해서 설명하겠습니다.
목차
- OCP, DIP정의
- 위반 사례
- 해결방안
정의
OCP(Open/closed priciple) : 확장에는 열려있으며 변경에는 닫혀있습니다.
DIP(Dependency inversion priciple) : 추상화에만 의존해야지, 구체화에 의존하면 안 됩니다.
이 정의만 봐서는 잘 이해가 안 됩니다. 따라서 코드를 가지고 설명하겠습니다.
회원 도메인입니다.
기능은 보시는 대로고, 회원 정보를 메모리에 저장 할 수도 있고, DB나 외부 시스템을 사용할 수 있기 때문에 미확정입니다.
클래스 다이어그램입니다.
그럼 위의 클래스 다이어그램의 MemberServiceImpl을 구현해봅시다.
public class MemberServiceImple implements MemberService{
private final MemberRepository memberRepository = new MemoryMemberRepository();
public void join(){...}
public Member findById(){...}
}
DIP 위반 상황
위의 코드에서 문제점이 뭘까요?
바로 아래 부분이 잘못됐습니다. MemberServiceImple에서는 추상화에만 의존해야 합니다. 하지만 아래 코드는 MemoryMemberRepository 같은 구현체에도 의존을 합니다.
따라서 DIP위반입니다.
private final MemberRepository memberRepository = new MemoryMemberRepository();
즉, 결론은 [그림 2]가 아니라 [그림 3]처럼 돼있기 때문에 DIP오류입니다.
OCP 위반 상황
그렇다면 프로젝트 중간에 기획자가 회원 저장소를 메모리가 아니라 DB를 사용한다고 해봅시다.
이때 코드는 아래처럼 바뀌게 됩니다
private final MemberRepository memberRepository = new DbMemberRepository();
방금처럼 플젝을 하다가 기획이 바뀌게 되어 확장을 하게 되는 상황이 발생했습니다.
이것은 어떤 것을 위반한 걸까요?
OCP위반입니다. 확장에는 열려있지만 코드를 바꾸었기 때문입니다.
해결법
자. 그러면 위 같은 문제점을 어떻게 해결할까요?
다음처럼 바꾸면 됩니다.
public class MemberServiceImple implements MemberService{
private final MemberRepository memberRepository;
public void join(){...}
public Member findById(){...}
}
하지만 문제는 있죠.
객체를 선언만 해주고 할당을 안 했기 때문에 null point exception이 발생합니다.
해결법은 다른 누군가가 MemoryMemberRepository, DbMemberRepository의 구현 객체를 대신 생성하고 주입하는 방법입니다.
AppConfig등장
우선 MemberServiceImple의 생성자 만들기
public class MemberServiceImple implements MemberService{
private final MemberRepository memberRepository;
MemberServiceImple(MemberRepository memberRepository){
this.memberRepository = new memberRepository();
}
public void join(){...}
public Member findById(){...}
}
그리고 AppConfing를 통해 구현체를 주입합니다.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
}
사용 클래스
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
}
}
위의 코드를 요약하면 그림 4처럼 됩니다. AppConfig클래스를 생성함으로써, 확장을 해도 코드를 변경하지 않아서 OCP를 만족하고, MemberServiceImpl이 MemoryMemberRepository구현체에 접근하지 않아서 DIP도 위반하지 않습니다.
결론
AppConfig의 등장으로 사용 영역과 구성 영역으로 구분이 됐습니다.
출처
김영한. 스프링 핵심 원리 - 기본편
'웹 > 백엔드, Spring' 카테고리의 다른 글
[Java] 스프링 컨테이너와 싱글톤 컨테이너 (0) | 2021.07.21 |
---|---|
[Java] IoC, DI, 컨테이너 (0) | 2021.07.21 |
[Java] Spring과 SOLID - 1편 (1) | 2021.07.19 |
[간단한 게시판 만들기] - 3. 게시글 쓰기 (0) | 2020.10.19 |
[간단한 게시판 만들기] - 2. 로그인 기능( 세션, 쿠키 설정) (0) | 2020.10.17 |