객체지향프로그래밍

SOLID 5원칙 - DIP 의존관계 역전 원칙(Dependency inversion principle)

쿠쿠s 2022. 1. 21. 14:36

프로그래머는 "추상화에 의존해야지, 구체화에 의존하면 안된다." 의존성 주입은 이 원칙을 따르는 방법 중 하나다.

쉽게 이야기해서 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻입니다. 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있습니다. 구현체에 의존하게 되면 변경이 아주 어려워집니다.

 

 

 

바로 DIP를 위반한 코드를 보여드리면서 설명 드리도록 하겠습니다.

 

interface Car{
    void rideCar();

}

class Tesla implements Car{
    @Override
    public void rideCar() {
        System.out.println("Tesla에 탑승했습니다.");
    }
}

class  Genesis implements Car {
    @Override
    public void rideCar() {
        System.out.println("Genesis에 탑승했습니다.");
    }
}

class Driver {

    private Car car = new Tesla();
    
    public void rideCar(){
        car.rideCar();
    }
}

public class People {

    public static void main(String[] args) {

        Driver driver = new Driver();
        driver.rideCar();
        
    }
}

출력 : Tesla에 탑승했습니다.

 

 

 

실행은 잘 되고 문제는 없어 보이지만 클라이언트인 Driver 클래스는 현재 Tesla 라는 구현체를 직접 의존하고 있습니다. 

    private Car car = new Tesla();

 

구체화에 의존하기 때문에 DIP를 위반하고 있는 코드입니다.

DIP를 위반하게 된다면 테슬라가 아닌 다른차를 타고 싶거나, 새로운 차가 추가된다면 계속 클라이언트(Driver)코드를 수정해야하는 일이 발생하여 OCP도 위반하게 됩니다. 그래서 DIP를 위반하지 않으려면 인터페이스(추상화)에만 의존하도록 설계를 변경해야합니다.

Config라는 구현객체를 생성하고, 연결하는 책임을 가지는 별도의 설정 클래스를 만들어서 해결해야 합니다.

 

 

Config 에서 구현 객체를 생성 -  Tesla,  

return new Driver(new Tesla());

 

 

Config 에서 생성한 return 값을 생성자를 통해서 주입해준다. Tesla -> Driver

    private final Car car;

    public Driver(Car car) {
        this.car = car;
    }

 

 

 

 

DIP원칙을 지킨 코드

interface Car{
    void rideCar();

}

class Tesla implements Car{
    @Override
    public void rideCar() {
        System.out.println("Tesla에 탑승했습니다.");
    }
}

class  Genesis implements Car {
    @Override
    public void rideCar() {
        System.out.println("Genesis에 탑승했습니다.");
    }
}

class Driver {

    private final Car car;

    public Driver(Car car) {
        this.car = car;
    }

    public void rideCar(){
        car.rideCar();
    }
}

class CarConfig{
    public Driver driver(){
        return new Driver(new Tesla());
    }
}

public class People {

    public static void main(String[] args) {
        CarConfig carConfig = new CarConfig();
        Driver driver = carConfig.driver();

        driver.rideCar();
    }
}

출력 : Tesla에 탑승했습니다.

 

 

 

이렇게 구현을 한다면 다른 차량이 추가, 변경이 이루어져도 Driver의 클래스는 수정을 하지 않아도 되고, 생성과 연결해주는 책임을 가지는 CarConfig의 클래스만 수정을 하면 되기 때문에 DIP원칙을 지킬 수 있습니다.

 

 

 

 

 

 

 

 

 

참고 -  김영한 스프링 핵심원리 기본편