많은 클래스가 하나 이상의 자원에 의존한다.
여기서 의존관계란 무엇일까?
'A가 B를 의존한다'의 의미는 의존대상 B가 변하면, 그것이 A에 영향을 미친다는 것이다.
예를 들어, 맞춤법 검사기는 사전에 의존하는데 이를 정적 클래스로 구현하면 아래와 같이 구현할 수 있다.
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) {...}
}
두 방식 모두 명시적 초기화를 사용하는데 이는 변경에 유연하지 않다.
SpellChecker 클래스가 여러 사전을 사용할 수 있도록 만들기 위해선 필드에서 final을 제거하고 다른 사전으로 교체하는 메서드를 추가할 수 있지만, 이는 오류를 내기 쉬우며 멀티쓰레드 환경에선 사용 불가능하다.
사용하는 자원에 따라 동작이 달라지는 클래스는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.
SpellChecker 클래스가 여러 사전을 지원해야 하며, 클라이언트가 원하는 사전을 사용해야 한다.
이 조건을 만족하는 패턴이 바로 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이다.
public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
public boolean isValid(String word) {...}
public List<String> suggestions(String typo) {...}
}
위와 같이 코드를 작성하면 dictionary라는 딱 하나의 자원만 사용하지만, 자원이 몇 개든 의존 관계가 어떻든 상관없이 잘 작동한다.
또한 불변을 보장하여 여러 클라이언트가 의존 객체를 안심하고 공유할 수 있다.
출처
- Effective Java