Item5
자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
1 개요
- 많은 클래스가 하나 이상의 자원에 의존한다.
- 가령 맞춤법 검사기(SpellChecker)는 사전(dictionary)에 의존하는데, 이런 클래스를 정적 유틸리티 클래스로 구현한 모습을 드물지 않게 볼 수 있다.
정적 유틸리티를 잘못 사용한 예
- 유연하지 않고 테스트하기 어렵다
- 사용할 사전이 단 한가지라고 가정하고 의존하는 객체를 클라이언트가 직접 생성하고 있기 때문
public class SpellChecker {
private static final Lexicon dictionary = ...;
private SpellChecker() {} // 객체 생성 방지
public static boolean isValid(String word) { ... }
public static List<String> suggestions (String typo) { ... }
}
싱글턴을 잘못 사용한 예
- 유연하지 않고 테스트하기 어렵다
- 사용할 사전이 단 한가지라고 가정하고 의존하는 객체를 클라이언트가 직접 생성하고 있기 때문
public class SpellChecker {
private final Lexicon dictionary = ...;
private SpellChecker() {}
public static SpellChecker INSTANCE = new SpellChecker(...);
public boolean isValid(String word) { ... }
public List<String> suggestions (String typo) { ... }
}
- 두 방식 모두 사전을 단 하나만 사용한다고 가정한다는 점에서 그리 훌륭해 보이지 않다.
- 실전에서는 사전이 언어별로 있을 수도 있고, 특수 어휘용 사전을 별도로 두기도 한다. 심지어 테스트용 사전이 필요할 수 있다.
- 사전 하나로 이 모든 쓰임에 대응할 수 있기를 바라는 것은 너무 순진한 생각이다.
클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 싱글턴(Singleton) 과, 정적 유틸리티(static util class)는 사용하지 않는 것이 좋다.
2 의존 객체 주입
- SpellChecker가 여러 사전을 사용할 수 있도록 만들어보자.
- 클래스(SpellChecker)가 여러 자원 인스턴스를 지원해야 하며, 클라이언트가 원하는 자원(dictionary)을 사용해야 한다.
- 의존 객체 주입 패턴은 아주 단순하여 수많은 프로그래머가 이 방식에 이름이 있다는 사실도 모른 채 사용해왔다.
- Dependency-Injection.md 참고