본문 바로가기

프로그래밍, 개발

객체지향설계원칙(SOLID) ⑤ - DIP

DIP

DIP는 Dependency Inveresion Principle, 의존성 역전 원칙을 말합니다.

In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details. The principle states: High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces). Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

객체지향설계에서 의존성 역전의 원칙은 소프트웨어 모듈들을 느슨하게 결합하는 구체적인 방법론입니다. 이 원칙을 따를 때, 고수준에서 저수준으로 향하는 전통적인 의존성 관계가 역전되고, 이에 따라 고수준의 모듈들을 저수준의 구현 상세내용들과 독립적으로 만들 수 있습니다. 이 원칙은 고수준의 모듈들은 저수준 모듈의 어떠한 것도 가져와서 사용할 수 없음을 명시합니다. 고수준과 저수준 모듈 모두는 추상화에 의존해야지, 구체화에 의존해서는 안 됩니다. 고수준 모듈은 추상화 계층에 의존하고, 저수준 모듈도 추상화 계층에 의존합니다.

Kid - Hamburger (추상화가 이루어지지 않은 상태)

public class Kid {

    private Hamburger food;

    public void setFood(Hamburger food) {
        this.food = food;
    }

    public void eat() {
        System.out.println("EAT " + food.toString());
    }
}
public class Main{
    public static void main(String[] args) {
        Hamburger hamburger = new Hamburger();
        Kid kid = new Kid();
        kid.setFood(hamburger);
        kid.eat();
    }
}

하지만 kid 말고 adult 에 대해 다루는 경우가 생길 수도 있고, 음식도 hamburger 만 있는 것이 아니라, ham, cheese 등 다양한 음식들에 대해 바꿔주어야 하는 경우가 생길 수 있다. 그럴 때 추상화에 의존하지 않고 구체 클래스에 의존하고 있는 상태라면, 예를 들어 음식이 바뀔 때, kid 클래스에 정의된 Hamburger 데이터 타입을 Ham, Cheese 등 구체 타입으로 일일이 변경해주어야 한다.

Person - Food (추상화가 이루어진 상태)

public class Kid implements Person {
    
    private Food food;

    public void setFood(Food food) {
        this.food = food;
    }

    public void eat() {
        System.out.println("EAT" + food.toString());
    }
}
public class Ham extends Food {
    public String toString() {
        return "Ham";
    }
}
public class Main{
    public static void main(String[] args) {
        Food ham = new Ham();
        Person kid = new Kid();
        kid.setFood(ham);
        kid.eat();
    }
}

여기서 kid 클래스에서 food 라는 인터페이스(추상화)를 바로 필드의 데이터 타입으로 갖고 있어서, 음식이 바뀔 때마다 kid 클래스의 필드 데이터 타입까지 바꿀 필요가 없어졌다. 이제 구체적인 구현이 아니라 추상화(인터페이스)에 종속적으로 된 것이다. 이를 통해, 구체 클래스의 변화가 발생해도 코드를 그대로 유지할 수 있게 되었다.