public class SpellChecker {
private Dictionary dictionary = new Dictionary();
public static boolean isValid(String word) {
...
return dictionary.contains(word);
}
}
SpellChecker라는 클래스에서 Dictionary 객체가 사용되는 상황을 생각해보자.
그런데 SpellChecker에서 언어별로 사전이 따로 있을 수도 있고, 특수 어휘용 사전을 별도로 두는 상황이 있을 수 있다. 이런 식으로 자원을 명시 (new로 생성)하면 어떤 단점이 있을까?
public class SpellChecker {
private Dictionary dictionary = new KoreanDictionary();
public static boolean isValid(String word) {
...
return dictionary.contains(word);
}
}
KoreanDictionary 객체로 바꾸고 싶다면 SpellChecker의 코드를 수정해야 한다. (OCP 법칙 위배)
SpellChecker를 테스트할 때 당연하게도 SpellChecker가 명시한 Dictionary 객체를 사용해야 한다.
1. Dictionary가 아닌 다른 자원을 쓰고 싶을 때도 별 다른 방법이 없다.
2. Dictionary 객체 생성 비용이 큰 경우라면? Dictionary 객체를 생성하지 않고 테스트해도 괜찮은 경우에도 Dictionary를 사용할 수 밖에 없다. (의미 없는 객체 생성 비용 발생)
인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주면 된다.
(이때 Dictionary라는 인터페이스를 만들어 구현체를 주입 받는다.)
public class SpellChecker {
private final Dictionary dictionary;
public SpellChecker(Dictionary dictionary) {
this.dictionary = dictionary;
}
public boolean isValid(String word) {
...
}
public List<String> suggestions(String typo) {
...
}
}
이렇게 생성자로 객체를 주입 받게되면 SpellChecker 객체 생성 시에 생성자가 딱 한 번 호출되는 것을 보장한다.
참고로 의존 객체 주입에는 생성자 주입, 필드 주입, Setter 주입, 일반 메서드 주입이 있는데 이에 관한 것 [Spring] DI를 하는 여러가지 방법을 참고하자!
@Test
void isValid() {
SpellChecker spellChecker = new SpellChecker(new KoreanDictionary);
spellChecker.isValid("test");
}
의존 객체 주입을 받으면 다음과 같이 코드를 사용하는 클라이언트 입장에서 객체를 설정할 수 있게 된다.
또한 SpellChecker 내부에는 구현체 코드가 없기 때문에, 나중에 구현체를 바꾸게 되어도 SpellChecker 코드 변경은 일어나지 않는다. (유연한 설계)
의존 객체 주입 방식의 변형으로 생성자에 자원 팩터리를 넘겨주는 방식이 있다.