서론
드디어 마지막 순서인 객체지향 설계 원칙(SOLID)의 DIP에 대해서 알아보자!
객체지향 설계 5대 원칙
- SRP(Single Responsibility Principle): 단일 책임 원칙
- OCP(Open Closed Priciple): 개방 폐쇄 원칙
- LSP(Liskov Substitution Priciple): 리스코프 치환 원칙
- ISP(Interface Segregation Principle): 인터페이스 분리 원칙
- DIP(Dependency Inversion Principle): 의존성 역전 원칙
DIP(Dependency Inversion Principle) - 의존성 역전 원칙이란?
DIP의 뜻을 정의한 내용은 아래와 같다.
"고수준 모듈은 저수준 모듈에 의존하면 안된다. 이 두 모듈 모두 다른 추상화된 것에 의존해야한다. 즉, 자신보다 변하기 쉬운것에 의존하지 마라"
이 정의를 말을 다시 말하면,
의존 관계를 맺을 때 변화하기 쉬운 것과 자주 변화하는 것 보다는 변화하기 어려운것과 거의 변화가 없는것에 의존하라는 원칙을 말한다.
이것을 적용시키기 위해서는 우선 변화하기 어려운 것을 알아야한다. 여기서 변화하기 어려운것을 말하는 것은 추상적인 객체(Interface, abstract)를 말한다.
예졔를 통해 이해해보자.
[예제]
[DIP 적용 전]
[예제 시나리오]
운전하고 싶은 차량(Car)을 탑승하여 운전(drive())을 할 때의 예제이다.
Truck (Class)
class Truck {
String drive() {
return "Truck";
}
}
Truck 클래스에서 운전을 하기 위해 drive()함수를 만들어주었다.
Van (Class)
class Van {
String drive() {
return "Van";
}
}
CarService (Class)
public class CarService {
private Truck car1;
private Van car2
public void setCar1(Truck car1) {
this.car1 = car1;
}
public void setCar2(Van car2) {
this.car2 = car2;
}
public String drive1() {
return car1.drive();
}
public String drive2() {
return car2.drive();
}
}
위와 같이 작성한다면, 차량의 종류가 추가될 때마다 setCar의 함수가 늘어날 수 밖에 없는 구조이다. 이러한 잘못된 구조를 변경하기 위해 아래와 같이 변화하지 않는 추상화 인터페이스를 하나 만들어 놓고 작업을 해야한다.
[DIP 적용 후]
Car (Interface)
public interface Car {
String drive();
}
Interface에서 공통 부분을 추상화한 함수인 drive()를 생성해준다.
Truck (Class)
public class Truck implements Car {
@Override
public String drive() {
return "Truck";
}
}
위와 같이 작업을 추상화한 인터페이스를 오버라이딩하여 작성해주었다.
Van (Class)
public class Van implements Car {
@Override
public String drive() {
return "Van";
}
}
위 처럼 Truck과 다른점은 없고 Car 인터페이스를 상속받는 구조는 똑같다.
CarService (Class)
public class CarService {
private Car car;
public void setCar(Car car) {
this.car = car;
}
public String drive() {
return car.drive();
}
public void print() {
System.out.println(car.drive());
}
}
MainController (Class)
public class MainController {
public static void main(String[] args) {
CarService carService = new CarService();
Car truck = new Truck();
Car van = new Van();
carService.setCar(truck);
carService.print();
carService.setCar(van);
carService.print();
}
}
결과
MainController에서 실행시 위와 같은 결과가 나온다.
위 처럼 Car라는 Interface를 만들어서 프로그램을 보다 더 확장성있게 만들어줄 수 있다. 또한, DIP를 잘 작성해주면 객체간의 관계를 최대한 느슨하게 해주는 효과도 있다.
"고수준 모듈은 저수준 모듈에 의존하면 안된다. 이 두 모듈 모두 다른 추상화된 것에 의존해야한다. 즉, 자신보다 변하기 쉬운것에 의존하지 마라"
앞서 말했던 정의와 비교하여 생각해보면,
예제에서 CarService가 고수준 모듈이 되고 Trcuk과 Van이 저수준 모듈이라하면 현재 이 둘은 서로 의존하지 않고 Car 인터페이스라는 추상화 된 것에 의존하게 만들어주었다고 보면된다.
이상 SOLID의 개념을 마무리지어보겠습니다.
'Programming > Java' 카테고리의 다른 글
[Java] Optional<T> 이란? (개념/ 종류 별/ 사용 방법/ 예제) (2) | 2022.05.21 |
---|---|
[Java] 함수형 프로그래밍 - Function Interface / Custom Functional Interface (개념 / 예제) (0) | 2022.05.12 |
[Java] SOLID - 인터페이스 분리 원칙 (ISP / Interface Segregation Principle)이란? (개념/ 예제) (0) | 2022.05.12 |
[JAVA] SOLID - 리스코프 치환 원칙 LSP(Liskov Substitution Principle) (1) | 2022.05.08 |
[JAVA] SOLID - 개방 폐쇄 원칙 OCP(Open Closed Principle) (0) | 2022.03.15 |
댓글