많은 클래스가 하나 이상의 자원에 의존한다. 예를 들어, 맞춤법 검사기는 사전(dictionary)에 의존하는데. 이를 정적 클래스로 구현하는 것은 좋지 않다.
아래는 예시이다.
정적 유틸리티
public class SpellChacker {
private static final Lexicon dictionary = ....;
private SpellChecker() {} // 객체 생성, 상속 방지
public static boolean isValid(String word) {...}
}
싱글턴
public class SpellChecker {
private final Lexicon dictionary = ...;
private SpellChecker INSTANCE = new SpellChecker(...);
public boolean isValid(String word) { ... }
}
두 클래스 모두 유연하지 않고 테스트하기가 어렵다. 만약 사전을 다른 언어의 사전을 만들고 싶다면 내부에 있는 dictionary 자체를 바꿔서 아예 다른 클래스를 생성해야 한다.
그러다보면 각 언어별 클래스를 생성해야 하는 번거로움이 생긴다.
필드에서 final을 제거하고 다른 사전으로 교체하는 메서드를 추가할 수도 있지만, 멀티스레드 환경에서는 쓸 수 없다.
사용하려는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.
이때 사용하기 좋은 것이 의존 객체 주입 패턴이다.클래스가 여러 자원 인스턴스를 지원할 수 있고 클라이언트가 원하는 자원을 사용할 수 있어야 한다.
의존 객체 주입 패턴이란, 인스턴스를 생성할 때, 필요한 자원을 넘겨줘서 생성하는 방식이다.
public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requeireNonNull(dictionary);
}
public boolean isValid(String word) {...}
}
실제로 자주 사용하는 spring 같은 프레임워크들이 이 패턴을 사용한다. 의존 객체 주입 패턴을 사용해서 이전 코드에서 유연성, 재사용성, 테스트 용이성을 순식간에 개선해줬다.