SOLID 원칙, 의존 역전의 원칙(Dependency Inversion Principle)

SOLID 원칙에서 'D'에 해당하는 의존 역전의 원칙에 대해서 간단히 확인해보겠습니다. 또한 이 원칙을 깨는 코드에 대해서 어떻게 리팩토링 하는지에 대해 확인해보겠습니다.

지금까지 SOLID 원칙 중 단일 책임의 원칙, 개방 폐쇄의 원칙, 리스코프 치환의 원칙, 인터페이스 분리의 원칙에 대해서 알아봤었습니다. 의존 역전의 원칙은 마지막 원칙으로 내용은 아래와 같습니다.

1. 고수준 모듈은 저수준 모듈에 의존해서는 안됩니다. 두 모듈 모두 추상화에 의존해야합니다.
2. 추상화는 디테일에 의존해서는 안되며 디테일은 추상화에 따라 달라집니다.

엥 뭔소리..? 하실겁니다.. 저도 그랬으니까요.. 일단 해당 원칙을 깨는 코드를 한번 볼까요??


당신은 현재 소프트웨어팀의 일원이고 프로젝트를 구현해야 합니다. 현재 소프트웨어 팀은 아래와 같은 클래스에 의해 구성되어 있습니다.

public class BackEndDeveloper {
    public void writeJava() { }
}

public class FrontEndDeveloper {
    public void writeJavascript() { }
}


그리고 우리의 프로젝트는 백엔드 개발자, 프론트엔드 개발자 클래스 타입을 아래와 같이 개발 프로세스에 사용하고 있다고 합시다.

public class Project {
    private BackEndDeveloper backEndDeveloper = new BackEndDeveloper();
    private FrontEndDeveloper frontEndDeveloper = new FrontEndDeveloper();

    public void implement() {
        backEndDeveloper.writeJava();
        frontEndDeveloper.writeJavascript();
    }
}

보시다시피 Project 클래스는 고수준 모듈이며 BackEndDeveloper 및 FrontEndDeveloper와 같은 저수준 모듈에 의존합니다. 우리는 실제로 의존 역전 원칙의 첫 번째 부분을 위반하고 있습니다.

또한 Project 클래스의 implement 메소드를 보았을 때, writeJava()와 writeJavascript() 메소드는 해당 클래스(BackendDeveloper, FrontEndDeveloper) 에 종속된 개발 내용이기 때문에 디테일에 해당합니다.(예를 들어, 백엔드를 Java로만 개발하지는 않을것이기 때문에) 따라서 두번째 부분을 위반하고 있습니다.

위의 문제를 해결하기 위해 코드를 리팩토링 해보겠습니다.


우선 Developer 인터페이스를 설계하였습니다.

public interface Developer {
    void develop();
}

이렇게 함으로써 간단히 추상화를 도입해보았습니다.

그 다음 BackEndDeveloper 클래스는 아래와 같이 리팩토링하였습니다.

public class BackEndDeveloper implements Developer {
    @Override
    public void develop() {
        writeJava();
    }
    
    private void writeJava() { }
    // 아마도 추가적으로 다른 언어들이 선언될 수 있을 것이다.
    private void writeKotlin() { }
    private void writePython() { }
    ...
}


FrontEndDeveloper 클래스는 아래와 같이 리팩토링하였습니다.

public class FrontEndDeveloper implements Developer {
    @Override
    public void develop() {
        writeJavascript();
    }

    public void writeJavascript() { }
}
 
다음 단계는 첫 번째 부분의 위반을 해결하기 위한 다음 단계는 BackendDeveloper 및 FrontEndDeveloper 클래스에 의존하지 않도록 Project 클래스를 리팩토링하는 것입니다.
package com.blackdog.solid.di;

import java.util.List;

public class Project {

    private List<Developer> developers;

    public Project(List<Developer> developers) {
        this.developers = developers;
    }

    public void implement() {
        developers.forEach(developer -> developer.develop());
    }
}

그 결과 Project 클래스가 하위 수준 모듈에 의존하지 않고 오히려 추상화에 의존하게 되었습니다. 또한 저수준 모듈(백엔드, 프론트엔드)은 각각의 세부내용을 추상화를 통해 구현하였습니다.

댓글

Designed by JB FACTORY