의존성주입과 의존관계역전원칙

HS K·2023년 2월 14일
0
post-custom-banner

의존성주입과 의존관계역전원칙

의존성주입(Dependency Injection)이란 메인 모듈(main mudule)이 ‘직접’ 다른 하위 모듈에 대한 의존성을 주기보다는 중간에 의존성 주입자(dependency injector)가 이 부분을 가로채 메인 모듈이 ‘간접’적으로 의존성을 주입하는 방식입니다.

이를 통해 메인 모듈과 하위모듈간의 의존성을 조금 더 느슨하게 만들 수 있으며 모듈을 쉽게 교체 가능한 구조로 만듭니다.

의존한다. 라는 의미

A가 B에 의존한다. = B가 변하면 A에 영향을 미치는 관계 = A - > B
를 의미하며 코드로는 이러한 것을 A가 B에 의존한다고 합니다.

import java.util.*;
class B {
    public void go() {
        System.out.println("B의 go()함수");
    }
}
class A {
    public void go() {
        new B().go();
    }
}
public class main {
    public static void main(String args[]) {
        new A().go();
    }
}
// B의 go()함수

자바 - Project 의 DI를 적용하지 않은 사례

프로젝트라는 클래스를 만든다고 한다고 가정하면 프론트엔드 개발자, 백엔드 개발자가 필요할 거고 이를 다음과 같은 코드로 구현할 수 있다.

import java.util.*;
class BackendDeveloper {
    public void writeJava() {
        System.out.println("자바가 좋아 인터네셔널~");
    }
}
class FrontEndDeveloper {
    public void writeJavascript() {
        System.out.println("자바스크립트가 좋아 인터네셔널~");
    }
}
public class Project {
    private final BackendDeveloper backendDeveloper;
    private final FrontEndDeveloper frontEndDeveloper;

	public Project(BackendDeveloper backendDeveloper, FrontEndDeveloper frontEndDeveloper) {
        this.backendDeveloper = backendDeveloper;
        this.frontEndDeveloper = frontEndDeveloper;
    }
    
    public void implement() {
        backendDeveloper.writeJava();
        frontEndDeveloper.writeJavascript();
    }
    public static void main(String args[]) {
        Project a = new Project(new BackendDeveloper(), new FrontEndDeveloper());
        a.implement();
    }
}

cf) 클래스 안에 있는 함수를 메서드라고 한다.

만약 class BackendDeveloper의 writeJava를 writeJavagorani로 바꾼다고 할때, implement()의 함수 이름도 바꿔줘야한다.

자바 - Project 의 DI 적용한 사례

여러명의 개발자를 추가할 수도 있으며 또 프론트엔드 개발자 말고 안드로이드 개발자 등으로 교체도 쉽게 할 수 있는 구조임을 보여준다.

또한 의존적인 화살표가 “역전" 된 것을 볼 수 있습니다.

DI를 하게 되면 의존관계역전원칙(Dependency Inversion Principle)이 적용된다는 뜻이다.

※ Develop이라는 인터페이스를 둬서 의존관계를 뒤집었다.

import java.util.*;
interface Developer {
    void develop();
}
class BackendDeveloper implements Developer {
    @Override
    public void develop() {
        writeJava();
    }
    public void writeJava() {
        System.out.println("자바가 좋아~ 새삥새삥");
    }
}
class FrontendDeveloper implements Developer {
    @Override
    public void develop() {
        writeJavascript();
    }
    public void writeJavascript() {
        System.out.println("자바스크립트가 좋아~ 새삥새삥");
    }
}
public class Project {
    private final List < Developer > developers;
    public Project(List < Developer > developers) {
        this.developers = developers;
    }
    public void implement() {
        developers.forEach(Developer::develop);
    }
    public static void main(String args[]) {
        List < Developer > dev = new ArrayList < > ();
        dev.add(new BackendDeveloper());
        dev.add(new FrontendDeveloper());
        Project a = new Project(dev);
        a.implement();
    }
}

의존관계역전원칙

의존성 주입을 할 때는 의존관계역전원칙(Dependency Inversion Principle)이 적용됩니다. 이는 2가지의 규칙을 지키는 상태를 말합니다.

  • 상위모듈은하위모듈에의존해서는안된다.둘다추상화에의존해야한다.
  • 추상화는 세부사항에 의존해서는 안 된다. 세부 사항은 추상화에 따라 달라져야한다.

의존성 주입의 장점

  1. 외부에서 모듈을 생성하여 dev.add(new BackendDeveloper()) 이런식으로 집어넣는 구조가 되기 때문에 모듈들을 쉽게 교체할 수 있는 구조가 됩니다.
  2. 단위 테스팅과 마이그레이션이 쉬워집니다.
  3. 애플리케이션 의존성 방향이 좀 더 일관되어 코드를 추론하기가 쉬워집니다.

의존성 주입의 단점

  1. 결국에는 모듈(여기에선 Develop)이 더 생기게 되므로 복잡도가 증가합니다.
  2. 종속성 주입자체가 컴파일을 할 때가 아닌 런타임 때 일어나기 때문에 컴파일을 할 때 종속성 주입에 관한 에러를 잡기가 어려워질 수 있다.

요약

의존관계를 잘 살펴보며 무엇을 수정해야하는지 알아야한다.


[부록] 의존성주입과 전략패턴의 차이

의존성주입이나 전략패턴 모두 “무언가를 쉽게 교체하기 위한 디자인패턴” 이며 같은 방식으로 작동한다.

  • 전략패턴: 의도에 초점을 맞추고 동일한 행동 계약을 준수하는 다양한 구현으로 인터페이스를 만들도록 권장하는 것을 포함한다.
  • 의존성주입 : 단지 일부 동작을 구현하고 의존성을 주입하기만 하는 패턴이다.
profile
주의사항 : 최대한 정확하게 작성하려고 하지만, 틀릴내용이 있을 수도 있으니 유의!
post-custom-banner

0개의 댓글