의존성 주입 (Dependency Injection)
의존성 주입을 설명하기 전에 의존 관계에 대해 먼저 알아야 합니다.
의존 관계(Dependency)
- A가 B에 의존한다
B의 상태가 바뀔 때 A의 영향을 미치는 것을 의존 관계라고 합니다.
public class SpellChecker {
private static final Dictionary dictionary = new DefaultDictionary();
private SpellChecker() {}
public static boolean isValid(String word) {
// TODO 여기 SpellChecker 코드
return dictionary.contains(word);
}
public static List<String> suggestions(String typo) {
// TODO 여기 SpellChecker 코드
return dictionary.closeWordsTo(typo);
}
}
현재 SpellCehcker는 Dictionary에 정적 팩터리 메서드방식으로 의존하고 있습니다.
만약 이 상황에서 기존에 우리가 영어 사전을 통해 스펠 체크를 하고있었는데 스페인어 사전으로 스펠체크를 해야한다면 어떻게 해야할까요?
의존성을 직접 변경하거나 스페인어 사전에 의존성을 가지고있는 또 하나의 객체를 만들어야합니다.
전세계에 언어가 수백개인데 각각 객체를 전부 만들 수 있을까요? 유지보수성은 어떨까요??
public class SpellChecker {
private final Dictionary dictionary = new DefaultDictionary();
private SpellChecker() {}
public static final SpellChecker INSTANCE = new SpellChecker();
public boolean isValid(String word) {
// ...
return dictionary.contains(word);
}
public List<String> suggestions(String typo) {
// ...
return dictionary.closeWordsTo(typo);
}
}
여전히 하나의 인스턴스에만 의존하기에 사전을 바꾸고자 할 때 코드를 수정해주거나 또 다른 SpellChecker 객체를 만들어야 합니다.
public class SpellChecker {
private final Dictionary dictionary;
public SpellChecker(Dictionary dictionary) {
this.dictionary = dictionary;
}
public SpellChecker(Supplier<Dictionary> dictionarySupplier) {
this.dictionary = dictionarySupplier.get();
}
public boolean isValid(String word) {
// TODO 여기 SpellChecker 코드
return dictionary.contains(word);
}
public List<String> suggestions(String typo) {
// TODO 여기 SpellChecker 코드
return dictionary.closeWordsTo(typo);
}
}
우리가 SpellCheckr를 사용하고자 할 때 원하는 사전을 넣어주면(주입해주면)됩니다.
이게 바로 의존성 주입(Dependency Injection) 줄여서 DI라고 합니다.
의존성 주입 방식으로 코드를 작성하면 사용하는 자원에 따라 동작이 달라지는 클래스를 만들 수 있습니다. 즉 유연성이 엄청나게 상승됩니다.
게다가 이를 통해 테스트 용이성도 높여줍니다.
만약 우리가 의존성 주입이 아닌 의존 관계를 가지는 코드를 작성했다고 가정해봅시다. 이때 우리가 진짜 사전을 가져와서 테스트하고 싶은게 아니라 모킹을 해서 테스트하고 싶은데 의존성이 있으면 모킹할 수가 없습니다. (static methode도 모킹하는 방법이 있지만 권장되지 않습니다.)
class SpellCheckerTest {
@Test
void isValid() {
assertTrue(SpellChecker.isValid("test"));
}
}
하지만 의존성 주입을 사용한다면 모킹된 사전을 가지고 테스트 할 수 있습니다.
class SpellCheckerTest {
@Test
void isValid() {
SpellChecker spellChecker = new SpellChecker(MockDictionary::new);
spellChecker.isValid("test");
}
}
'정보' 카테고리의 다른 글
🎯 Item 7 - 다 쓴 객체 참조를 해제하라 (0) | 2024.03.17 |
---|---|
[Effective java] Item 6 불필요한 객체 생성을 피하라 (0) | 2024.03.10 |
[Effective java] Item 4 인스턴스화를 막을려거든 private 생성자를 사용하라 (0) | 2024.02.25 |
[Effective java] Item 1 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2024.02.18 |
싱글톤 (0) | 2023.11.26 |