- 다른 것에 의지하여 존재함.
- 어떤 프로그램이나 실체의 정의와 기능이 전적으로 특정한 하드웨어와 소프트웨어 또는 앞서 진행된 이벤트나 상황에 의존하거나 종속적인 상태.
의존성은 굉장히 포괄적인 단어다. 프로그래밍에 적용해 봐도 라이브러리 간 의존성, 객체 간 의존성, 패키지 간 의존성 등 하나의 요소가 다른 요소에 의존하거나 종속적인 상태라면 적용 가능하다.
어느 한 요소가 완전히 독립적이지 않고 다른 요소와 상호작용, 즉 어느정도 영향을 주고 받으면 의존성이 있다고 말할 수 있다.
OOP 로 범위를 좁혀서 의존 관계를 정의해보자면 두 가지로 정의할 수 있다.
프로그래밍에서 정적(static) 은 컴파일 시점을 의미한다.
클래스 사이에 의존 관계가 생긴 것을 의미한다.
Printer
클래스는 System
클래스의 out
정적 변수에 의존하고 있다.
Printer
컴파일 시점에 System
클래스의 out
에 대한 구체적인 정보가 있어야 컴파일 된다.
public class Printer {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
프로그래밍에서 동적(dynamic) 은 runtime, 즉 프로세스가 실행중인 상태를 의미한다.
동적인 의존관계는 실행중에 의존 관계를 다이나믹 하게 결정하는 것이다.
A → B 의존 관계가 있을 때, 컴파일 시점에 A는 의존할 구체적인 대상 B에 대해 알지 못하고
런타임 시에 구체적인 B와 의존 관계를 맺는다.
Porsche 는 클래스 레벨에서는 어느 회사의 GasPump 로 기름을 공급 받을 지 모른다.
런타임시에 SOil 이냐 SK 냐 의존 관계가 결정된다.
의존 관계는 fuel(GasPump soil)
메서드 에서 보듯이, 의존 대상 객체의 참조값을 사용할 때 맺어진다.
이 참조값엔 구체적인 의존 대상 객체 정보가 들어있다.
Porsche 는 SOil 참조값을 사용할 수도 있고 SK 참조값을 사용할 수도 있다.
즉 다형성을 가능하게 해주는 기술인 다이나믹 바인딩 덕분에 가능하다.
class Porsche {
GasTank gasTank;
void fuel(**GasPump gasPump**){
gasTank.up(gasPump.supply(20));
}
}
interface GasPump {
int supply(int liter)
}
class SOil implement GasPump {
int supply(int liter){
// 바가지로 주유한다
}
}
class ㅊ implement GasPump {
int supply(int liter){
// 주유 기계로 주유한다
}
}
동적인 의존 관계는 의존 대상 객체의 참조값을 사용할 때 결정된다고 했다.
의존 관계 주입은 바로 이 참조값을 전달하는 방법이다.
class Porsche {
GasTank gasTank;
void fuel(){
Sk sk = new Sk();
gasTank.up(sk.supply(20));
}
}
위 코드는 의존 주체가 직접 의존 대상 객체의 참조값을 사용하고 있다.
의존 관계 주입은 제 3자로 부터 참조값을 전달 받는 것이다.
주유소
클래스가 포르쉐에게 전달할 구체적인 GasPump 객체를 결정하고 전달하고 있다.
class 주유소 {
public void static main(String[] args){
Porsche porsche = new Porsche();
Avante avente = new Avante();
porsche.fuel(new SK());
porsche.fuel(new SOil());
}
}
class Porsche {
GasTank gasTank;
void fuel(**GasPump gasPump**){
Sk sk = new Sk();
gasTank.up(sk.supply(20));
}
}
이렇게 의존관계에 있는 의존 주체가 의존할 대상을 직접 결정하는 것이 아니라 제 3자가 결정해서 참조값을 주입하는 것을 의존관계 주입이라 한다.
포르세가 어떤 주유기를 사용할지 스스로 선택하지 않고 주유소에 의해 제어 당했다.
제어의 역행은 제어 흐름 구조가 뒤바뀌는 것을 말한다.
제어의 역행의 장점은 객체가 자신의 관심사에만 집중할 수 있게 한다. 의존 대상의 구체적인 정보는 모르게 함으로써 의존 대상의 변경에는 닫혀있고 자신의 변경에는 열려 있다.
스프링 프레임워크에는 IoC 개념을 구현한 IoC 컨테이너 오브젝트가 있다.
IoC 컨테이너는 DI 를 편하게 적용할 수 있도록 싱글톤 레지스트리나 다양한 구성정보 설정 매커니즘을 보유하고 있다.