어떤 클래스는 다른 클래스에 대한 참조가 필요한 경우가 있습니다. 예를 들어, A클래스가 B 클래스의 참조가 필요합니다. 이 때 A가 B에 의존하고 있다고 말하고, B를 A의 종속 항목(디펜던시) 이라고 합니다.
"A가 B를 의존한다"라는 것은 의존 대상인 B가 변하면, 그것이 A에 영향을 미치는 것 입니다. 즉, B의 기능이 추가 또는 변경되거나 형식이 바뀌면 그 영향이 A에 미칩니다.
이렇게 상호간에 영향을 주고 받을 수 있으면 강한 결합이라고 합니다. 아래에 예시를 들어보겠습니다.
public class Toy {
private NomalBattary nomalbattary;
public Toy() {
this.nomalbattary = new NomalBattary();
}
public void Toystart() {
nomalbattary.Use();
}
}
public class NomalBattary {
public void Use() {
System.out.println("일반배터리를 사용합니다.");
}
}
Toy 클래스의 멤버 변수 타입으로 NomalBattary 클래스가 존재하는 것을 확인할 수 있습니다. 이 코드는 내부적으로 문제의 소지가 있습니다. 만약 NomalBattary 클래스가 다른 종류의 배터리 클래스(ex 전기배터리 수소배터리 등)로 변경되는 상황이라면 Toy 클래스의 코드가 같이 변경됩니다. 즉, Toy 클래스가 NomalBattary 클래스에 의존하게 됩니다. 따라서 Toy 클래스가 NomalBattary 클래스에 의존성이 존재한다고 하게 됩니다.
다른 예를 보겠습니다. Toy 클래스 안의 NomalBattary 클래스를 ElectricBattary 클래스로 변경한다고 하면 코드의 변경은 다음과 같을 것 입니다.
public class Toy {
private NomalBattary nomalbattary; -> private ElectricBattary electricbattary;
public Toy() {
this.nomalbattary = new NomalBattary(); -> this.electricbattary = new ElectricBattary();
}
public void Toystart() {
nomalbattary.Use(); -> electricbattary.Use();
}
}
public class ElectricBattary {
public void Use() {
System.out.println("전기배터리를 사용합니다.");
}
}
public class NomalBattary {
public void Use() {
System.out.println("일반배터리를 사용합니다.");
}
}
위 변화를 보면, 멤버 변수 타입(클래스) 하나만 바꿨을 뿐인데 Toy 클래스에 있는 많은 코드가 변경 됩니다. 그렇기 때문에 강한 결합(강한 의존성) 이라고 하는 것이며, 이는 유지보수 및 코드의 안정성 측면에서 굉장히 좋지 않은 케이스라고 할 수 있습니다.
위와 같은 문제 해결을 위해서 객체 간의 강한 결합을 약한 결합으로 바꾸는 방법을 알아보겠습니다. 방법은 인터페이스(Interface)를 활용하는 것 입니다.
public interface Battary {
void Use();
}
public class NomalBattary implements Battary {
@Override
public void Use() {
System.out.println("일반배터리를 사용합니다.");
}
}
public class ElectricBattary implements Battary {
@Override
public void Use() {
System.out.println("전기배터리를 사용합니다.");
}
}
public class Toy {
private Battary battary;
public Toy(Battary battary) {
this.battary = battary;
}
public void Toystart() {
battary.Use();
}
}
위와 같이 Battary 인터페이스를 만들어 Use()의 추상 메서드를 선언하여 NomalBattary 클래스와 ElectricBattary 클래스에서 Use()를 구현하게 하면, NomalBattary와 ElectricBattary 오브젝트는 모두 Battary 타입에 대입될 수 있으므로 Toy 클래스에서 멤버변수 타입을 Battary로 할 수 있게 됩니다.
이는 Toy 클래스 내부적으로 코드의 변경이 일어날 필요 없이, 생성자를 통해 객체를 받아 멤버변수에 대입하기만 하면 오브젝트를 변경 가능하게 해줍니다. 즉, 상호간의 종속성에서 벗어나 약한 결합을 이루게 해줍니다.
위 내용은 DI를 이해하기 전 사전 지식으로 알아야하는 내용입니다.
흔히 DIP(Dependency Inversion Principle) 이라고 불리는 OOP의 SOLID 원칙중 하나이며, 고수준의 모듈은 절대로 저수준의 모듈의 구현에 대해서 의존을 해서는 안된다(특히, 강한 결합을 통한 의존은 지양해야한다) 라는 것에 관한 내용이죠!