의존성주입(DI, Dependency Injection)과 의존관계역전원칙(DIP, Dependency Inversion Principle)
의존성주입(DI, Dependency Injection)
의존성주입(DI, Dependency Injection)이란 메인 모듈(main mudule)이 ‘직접’ 다른 하위 모듈에 대한 의존성을 주기보다는 중간에 의존성 주입자(dependency injector)가 이 부분을 가로채 메인 모듈이 ‘간접’적으로 의존성을 주입하는 방식
![](https://blog.kakaocdn.net/dn/bNxvOh/btssOsWZoWp/84Av0oxCTEM7PQzpyHjqt1/img.png)
이를 통해 메인 모듈과 하위 모듈간의 의존성을 조금 더 느슨하게 만들 수 있으며 모듈을 쉽게 교체 가능한 구조로 만듬
'의존한다' 라는 의미
A가 B에 의존한다. == B가 변하면 A에 영향을 미치는 관계 == A → B 를 의미 (B가 변경이 되면, A도 변경이 되어야 함)
코드로는 이러한 것을 A가 B에 의존한다고 함
import java.util.*;
class B { // B 코드가 수정이되면 A 코드도 수정이 되어야 함
public void go() {
System.out.println("B의 go()함수");
}
}
class A {
public void go() {
new B().go(); // 클래스 B의 go 함수를 호출
}
}
public class main {
public static void main(String args[]) {
new A().go();
}
}
// B의 go()함수
프로젝트의 DI를 적용하지 않은 사례
프로젝트라는 클래스를 만든다고 가정
![](https://blog.kakaocdn.net/dn/bKO21S/btssUa1Ljqo/otLb1EyOeXwgyKvOqLLpEk/img.png)
프론트엔드 개발자, 백엔드 개발자가 필요하고 이를 다음과 같은 코드로 구현
클래스 총 3개
1. BackendDeveloper
2. FrontEndDeveloper
3. Project
BackendDeveloper와 FrontEndDeveloper의 함수가 변경이되면 Project 에서 호출하는 메서드도 변경을 해줘야함
즉, Project는 BackendDeveloper와 FrontEndDeveloper에 의존함
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(); //실행
}
}
프로젝트의 DI를 적용한 사례 (DI 적용)
여러명의 개발자를 추가할 수도 있으며 또 프론트엔드 개발자 말고 안드로이드 개발자 등으로 교체도 쉽게 할 수 있는 구조임을 보여줌. 또한 의존적인 화살표가 “역전"된 것을 볼 수 있음
DI를 하게 되면 의존관계역전원칙(Dependency Inversion Principle)이 적용되는 것
FrontendDeveloper의 writeJavascript() 함수를 변경하면, develop() 의 writeJavascript()만 수정해주면 됨
별도로 Project 클래스의 메서드를 수정할 필요 없음
import java.util.*;
interface Developer {
void develop();
}
class BackendDeveloper implements Developer { //Developer로부터 파생
@Override
public void develop() {
writeJava();
}
public void writeJava() {
System.out.println("자바가 좋아~ 새삥새삥");
}
}
class FrontendDeveloper implements Developer { //Developer로부터 파생
@Override
public void develop() {
writeJavascript(); //2. develop()만 수정하면 됨
}
public void writeJavascript() { // 1. 수정을 하게 되더라도
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); //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();
}
}
의존관계역전원칙(DIP, Dependency Inversion Principle)
의존성 주입을 할 때는 의존관계역전원칙(DIP, Dependency Inversion Principle)이 적용
이는 2가지의 규칙을 지키는 상태
- 상위 모듈은 하위 모듈에 의존해서는 안되고, 둘다 추상화에 의존해야 함
- 추상화는 세부사항에 의존해서는 안되고, 세부 사항은 추상화에 따라 달라져야 함
의존성 주입의 장점
1. 외부에서 모듈을 생성하여 dev.add(new BackendDeveloper()) 이런식으로 집어넣는 구조가 되기 때문에 모듈들을 쉽게 교체할 수 있는 구조가 됨
2. 단위 테스팅과 마이그레이션이 쉬워짐
3. 애플리케이션 의존성 방향이 좀 더 일관되어 코드를 추론하기가 쉬워짐
마이그레이션 : 다른 운영 환경으로 이동하는 것(DB이동, 데이터 이동 등)
의존성 주입의 단점
1. 결국에는 모듈이 더 생기게 되므로 복잡도가 증가
2. 종속성 주입 자체가 컴파일을 할때가 아닌 런타임 때 일어나기 때문에 컴파일을 할 때 종속성 주입에 관한 에러를 잡기가 어려워질 수 있음
* 참고
- CS 지식의 정석 | 디자인패턴 네트워크 운영체제 데이터베이스 자료구조 -인프런
'CS > 디자인패턴' 카테고리의 다른 글
[CS] 옵저버 패턴 (0) | 2023.09.06 |
---|---|
[CS] 전략 패턴 (0) | 2023.09.05 |
[CS] 이터레이터 패턴 (0) | 2023.09.02 |
[CS] 팩토리 패턴 (0) | 2023.09.01 |
[CS] 싱글톤 패턴을 구현하는 7가지 방법 (0) | 2023.08.31 |
댓글