•
Dependency Injection 이란 메인 모듈이 직접 다른 하위 모듈에 대한 의존성을 가지고 있기 보다는, 중간에 의존성 주입자 (dependency injector) 가 이 부분을 가로채 메인 모듈이 간접적으로 의존성을 주입하는 방식을 말한다.
•
이를 통해서 메인 모듈과 하위 모듈간의 의존성을 조금 더 느슨하게 만들 수 있으며 모듈을 쉽게 교체 가능한 구조로 만든다.
의존한다는 의미
•
A가 B에 의존한다 = B가 변하면, A도 변한다.
•
아래 코드의 경우, Hi는 Hello 클래스에 의존하고 있는데, 만약 Hello 클래스의 greet 에 매개변수나 다른 요소들이 추가되면, Hi 클래스도 그에 맞춰 같이 바뀌어져야한다.
package me.whiteship.designpatterns;public class DependencyInjectionApp { public static void main(String[] args) { new Hi().greet(); }}class Hello { public void greet() { System.out.println("greetings from b"); }}class Hi { public void greet() { new Hello().greet(); }}
Java
복사
Dependency Injection 예시
—>
•
DI 적용하지 않고 바로 구현했을 때
public class DINotApplied { public static void main(String[] args) { Project project = new Project(new BackendDeveloper(), new FrontendDeveloper()); project.implement(); } private static class BackendDeveloper { public void writeJava() { System.out.println("coding with java"); } } private static class FrontendDeveloper { public void writeJs() { System.out.println("coding with javascript"); } } private static 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.writeJs(); } }}
Java
복사
DI 적용하여 구현했을 때
package me.whiteship.designpatterns._04_di;import java.util.ArrayList;import java.util.List;public class DIApplied { public static void main(String[] args) { List<Developer> developers = new ArrayList<>(); developers.add(new BackendDeveloper()); developers.add(new FrontendDeveloper()); Project project = new Project(developers); project.implement(); } interface Developer { void develop(); } static class BackendDeveloper implements Developer { @Override public void develop() { writeJava(); } void writeJava() { System.out.println("coding with java"); } } static class FrontendDeveloper implements Developer { @Override public void develop() { writeJs(); } private void writeJs() { System.out.println("coding with javascript"); } } static class Project { private final List<Developer> developers; public Project(List<Developer> developers) { this.developers = developers; } public void implement() { developers.forEach(Developer::develop); } }}
Java
복사
자세히보기
•
위와 같이 구현하면 새로운 개발자 유형 (안드로이드, IOS 등)이 추가되어도 크게 수정하지 않고 바로 적용이 가능하다.
의존 관계 역전 원칙(Inversion of Dependency Injection)
•
의존성 주입시에는 의존관계역전원칙이 적용된다. 이는 아래의 2가지가 충족되는 상황을 말한다.
◦
상위 모듈은 하위 모듈에 의존해서는 안된다. 둘다 추상화에 의존해야한다.
◦
추상화는 세부사항에 의존해서는 안된다. 세부사항은 추상화에 따라 달라져야한다.
의존성 주입의 장점
•
외부에서 모듈을 생성해서 집어넣는 구조가 되기 때문에 모듈을 쉽게 교체할 수 있게 된다.
◦
위의 예에서 BackendDeveloper -> FrontDeveloper -> AppDeveloper 등 손쉽게 교체가 가능하다.
•
단위 테스트와 마이그레이션이 쉬워진다.
•
어플리케이션 의존성 방향이 좀 더 일관되어 코드를 추론하기가 쉬워진다.
의존성 주입의 단점
•
모듈이 더 생기는 것이므로 코드가 복잡해진다.
•
종속성 주입이 런타임에 일어나기 때문에 컴파일 할 때에는 종속성 주입에 관한 에러를 사전에 잡기가 어려워진다.