객체지향설계 5가지 원칙
일반적인 접근 방식 (DIP를 따르지 않는 경우)
class LightBulb {
void turnOn() {
System.out.println("LightBulb: Bulb turned on...");
}
void turnOff() {
System.out.println("LightBulb: Bulb turned off...");
}
}
class ElectricPowerSwitch {
private LightBulb lightBulb;
public ElectricPowerSwitch(LightBulb lightBulb) {
this.lightBulb = lightBulb;
}
void press() {
System.out.println("Switch pressed");
lightBulb.turnOn();
}
}
위의 예시에서 ElectricPowerSwitch는 LightBulb 클래스에 의존적입니다. 즉, 다른 종류의 전구나 전원을 다루려면 새로운 클래스를 만들거나 기존 클래스를 수정해야 하므로 확장성이 떨어집니다.
의존 역전 원칙을 적용한 접근 방식
interface Switchable {
void turnOn();
void turnOff();
}
class LightBulb implements Switchable {
@Override
public void turnOn() {
System.out.println("LightBulb: Bulb turned on...");
}
@Override
public void turnOff() {
System.out.println("LightBulb: Bulb turned off...");
}
}
class ElectricPowerSwitch {
private Switchable device;
public ElectricPowerSwitch(Switchable device) {
this.device = device;
}
void press() {
System.out.println("Switch pressed");
device.turnOn();
}
}
Switchable은 추상화(인터페이스)를 제공하고, ElectricPowerSwitch와 LightBulb 모두 이 추상화에 의존합니다. 이로 인해 ElectricPowerSwitch는 이제 LightBulb에 직접적으로 의존하지 않게 되어 다양한 Switchable 객체를 다룰 수 있게 됩니다. 이는 코드의 유연성과 확장성을 향상시킵니다.
예제에서의 "저수준 모듈(Low-level Module)"은 LightBulb 클래스입니다. 이 모듈은 개별 기능(전구 켜기, 끄기)을 수행하는 실제 로직을 구현합니다. 이러한 저수준 모듈은 실제 '일'을 하는 모듈이라고 생각할 수 있습니다.
"고수준 모듈(High-level Module)"은 ElectricPowerSwitch 클래스입니다. 이 모듈은 저수준 모듈인 LightBulb을 사용하여 더 복잡한 기능(스위치 누르기)을 구현합니다. 고수준 모듈은 비즈니스 로직이나 사용자 인터페이스 등을 관리하고, 여러 저수준 모듈을 조합하여 더 큰 기능을 구현하는 모듈이라고 생각할 수 있습니다.
"의존 역전 원칙(Dependency Inversion Principle)"을 적용하면, 고수준 모듈인 ElectricPowerSwitch는 저수준 모듈인 LightBulb에 직접적으로 의존하지 않습니다. 대신, 둘 다 Switchable이라는 추상화(인터페이스)에 의존하게 됩니다. 이로써 고수준 모듈과 저수준 모듈 사이의 결합도가 낮아지고, 유지보수와 확장성이 향상됩니다.