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
코드 변경은 일어나지 않는다. (유연한 설계)
의존 객체 주입 방식의 변형으로 생성자에 자원 팩터리를 넘겨주는 방식이 있다.