April 05, 2022
많은 클래스가 하나 이상의 자원에 의존한다.
아래 두 가지 경우는 잘못 사용의 예이며, 유연하지 않고 테스트하기 어렵다.
정적 유틸리티 클래스로 구현하는 경우
public class SpellChecker {
private static final Lexicon dictionary = ...;
private SpellChecker() {} // 객체 생성 방지
public static boolean isValid(String word) { ... }
public static List<String> suggestions(String type) { ... }
}
싱글턴으로 구현하는 경우
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 type) { ... }
}
위의 두 방식 모두 사전을 단 하나만 사용한다고 가정한다는 점에서 훌륭해보이지 않다.
SpellChecker가 여러 사전을 사용할 수 있도록 만들어보자.
필드에서 final 한정자를 제거하고 다른 사전으로 교체하는 메서드를 추가할 수 있다.
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 type) { ... }
}
의존 객체 주입 패턴은
이 패턴의 쓸만한 변형으로, 생성자에 자원 팩터리를 념겨주는 방식이 있다.
팩터리란 호출할 때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체를 말한다.
Supplier<T>를 입력받는 메서드는 일반적으로 한정적 와일드카드 타입(bounded wildcard type)을 사용해 팩터리의 타입 매개변수를 제한해야 한다. 이 방식을 사용해 클라이언트는 자신이 명시한 타입의 하위타입이라면 무엇이든지 생성할 수 있는 팩터리를 넘길 수 있다.
Mosaic create(Supplier<? extends Tile> tileFactory) { ... }
의존 객체 주입이 유연성과 테스트 용이성을 개선해주긴 하지만, 의존성이 수 천 개나 되는 큰 프로젝트에서는 코드를 어지럽게 만들기도 한다.
-> 의존 객체 프레임워크를 사용하면 해소할 수 있다. (Spring!🌼)