DIP?
DIP는 다음과 같은 정의를 가지고 있습니다
- 상위 모듈은 하위 모듈에 의존해서는 안된다
- 추상화는 세부 사항에 의존해서는 안된다
정말 아무리봐도 무슨말인지 모르겠죠?
조금 쉽게 설명하자면 DIP의 핵심은
의존 관계를 맺을 때 변화하기 쉬운 것에 의존하기보다는, 변화하지 않는 것에 의존하라는 원칙입니다!
현실 세계를 예로 들어 볼까요
내가 PayService를 개발하고 싶은 개발자라고 가정해봅시다
Pay수단에는 되게 여러가지 방법이 있겠죠?
SamsungPay, KaKaoPay, NaverPay ... 기타 등등
그러면 개발자의 입장에서 위 Pay수단중에서 하나 골라서 사람들에게 Service를 제공한다고 가정합시다.
하지만 사람들의 요구사항에 의해서 다른 Pay수단들도 추가해달래요!
초기 설계때 딱 하나의 Pay수단만 가지고 메서드를 구현했다면,,
참 확장에 어려운 설계가 아닌가 싶습니다
그러지 말고 확장하기 편하게 공통부분을 묶어서 변화하지 않게 설정하는 것이죠!
자 그러면 Code를 예로 들어볼게요~
Code 예시
먼저, 잘못된 설계부터 예시를 들어볼게요
개발자가 SamsungPay를 택했어요!!
package solid.dip;
class SamsungPay {
String payment() {
return "samsung";
}
}
이를 바탕으로 PayService를 만들었습니다!
package solid.dip;
public class PayService {
private SamsungPay pay;
public void setPay(final SamsungPay pay) {
this.pay = pay;
}
public String payment() {
return pay.payment();
}
}
정말 간단하죠?
하지만 문제가 있다면, 요구사항이 바뀌어서 다른 PayService를 만들라고 하면
그때마다 메서드를 하나씩 만들어야 겠네요 ㅠㅠ
너무 구리죠?
그래서 리팩토링 합시다~!
먼저 공통부분을 추상화 한 Interface를 만들게요!
package solid.dip;
public interface Pay {
String payment();
}
그러면 SamsungPay를 리팩토링 할 수 있어요!
package solid.dip;
class SamsungPay implements Pay {
@Override
public String payment() {
return "samsung";
}
}
그 다음은 사람들의 요구사항을 반영한 KakaoPay도 만들어볼까요?
package solid.dip;
public class KakaoPay implements Pay {
@Override
public String payment() {
return "kakao";
}
}
마지막으로 PayService를 리팩토링 해볼게요!!
package solid.dip;
public class PayService {
private Pay pay;
public void setPay(final Pay pay) {
this.pay = pay;
}
public String payment() {
return pay.payment();
}
}
이러한 설계가 가능해집니다!
사용자의 입맛대로 Pay를 고를수가 있겠네요!
테스트해볼까요?
package solid.dip;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class PayServiceTest {
private PayService payService = new PayService();
@Test
void 삼성페이가_올바르게_결제되는지_테스트() {
/* Given */
Pay samsungPay = new SamsungPay();
/* When */
payService.setPay(samsungPay);
/* Then */
assertThat(payService.payment()).isEqualTo("samsung");
}
@Test
void 카카오페이가_올바르게_결제되는지_테스트() {
/* Given */
Pay kakaoPay = new KakaoPay();
/* When */
payService.setPay(kakaoPay);
/* Then */
assertThat(payService.payment()).isEqualTo("kakao");
}
}
네 테스트가 다 통과됩니다!
마지막으로, 전체 UML을 보시면서 Code 예시는 마무리 할게요~!
마무리
DIP가 중요한 이유는 확장성이 용이하다는 것 입니다!
또한 객체간의 관계를 최대한 느슨하게 해주는 효과가 있습니다!
그래서 다양한 설계 방식, 혹은 복잡한 시스템 설계가 가능하게 되는 것이죠!
참고
의존관계 역전 원칙
'Developer > Kotlin & Java' 카테고리의 다른 글
Java8 - Stream과 함수형 인터페이스(lambda 표현식)에 대해서 (0) | 2020.05.01 |
---|---|
자바 직렬화 - Java Serialization (0) | 2020.03.20 |
SOLID - ISP(Interface Segregation Principle)란? : 인터페이스 분리 원칙 (6) | 2019.11.26 |
SOLID - LSP(Liskov Substitution Principle)이란? 리스코프 치환 원칙 (0) | 2019.11.22 |
SOLID - OCP(Open Closed Principle) : 개방 폐쇄 원칙 (0) | 2019.11.17 |