지난번 OCP 정리에 이어 이번에는 의존 역전 원칙인 DIP에 대해 간단히 정리하겠다.
정의
우선, 책에 정리되어 있는 정의는 다음과 같다.
자신보다 변하기 쉬운 것에 의존하던 것을 추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 변화에 영향받지 않게 하는 원칙
말을 굉장히 어렵게 써놨는데 쉽게 풀어서 설명하면 "구현체가 아닌 역할군에 의존관계를 가져야 한다"는 원칙이다.
역할과 구현체
위 말도 무슨 말인가 싶을 수 있는데, 객체지향 프로그래밍을 공부해보면 무슨 말인지 바로 이해가 될 것이다.
우선, 객체지향 설계를 할 경우 다음과 같은 방식으로 진행된다.
- 해당 기능을 담당하는 역할을 설계(인터페이스)
- 해당 기능을 담당하는 역할을 상속받아 실제로 구현체를 구현(클래스)
다음 사진을 한번 보자.
로미오와 줄리엣이라는 작품에는 로미오라는 역할과 줄리엣이라는 역할이 존재한다.
로미오 역할을 담당하기 위해 장동건이 연기할 수도 원빈이 연기할수도 있다. 줄리엣 역할 또한 마찬가지다.
이때 로미오 역할을 맡은 장동건 배우가 줄리엣 역할을 기반으로 상대 연기를 준비하지 않고 줄리엣 역을 맡을 김태희 배우를 기반으로 상대 연기를 준비한다면 어떻게 될까?
줄리엣 연기 담당이 송혜교로 바뀔 경우 장동건 배우는 다시 그에 맞춰 연기를 준비해야 한다.
이러한 불상사를 막기 위해 상대 배우가 아닌 역할에 기반하여 의존성을 갖는 것이 바로 DIP 원칙이다.
예시 코드
아래 코드를 한번 보자.
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
회원가입과 조회 기능을 담당하는 서비스이다.
그리고 이 서비스는 MemoryMemberRepository라는 회원 구현체에 의존성을 가지고 있다.
하지만 이렇게 코드를 작성할 경우 DIP 원칙에 위배된 설계가 되는 것이다.
이를 해결한 아래 코드를 보자.
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
이 코드는 memberRepository라는 인터페이스에는 의존성이 있지만 MemoryMemberRepository라는 구현체와는 의존관계가 없다.
이처럼 구현체가 아닌 역할에 의존성을 갖게 설계하는 것이 DIP 원칙을 지키는 설계 방식이다.
참고자료
'CS > 디자인 패턴과 프로그래밍 패러다임' 카테고리의 다른 글
SOLID 원칙 - 개방 폐쇄 원칙 (2) | 2024.12.17 |
---|---|
객체지향 프로그래밍 (0) | 2024.06.24 |
프로그래밍 패러다임 (0) | 2024.06.24 |
싱글톤 패턴(Singleton Pattern) (0) | 2024.06.21 |
디자인 패턴 (0) | 2024.06.19 |