public class SpellChecker {
private static final Lexicon dictionary ...; // 정적 자원
private SpellChekcer() {} // 객체 생성 방지
public static boolean isValid(String word) { ... }
public static List<String> suggestions(String typo) { ... }
싱클턴 (#3)
코드 5-2 싱글턴을 잘못 하용한 예 - 유연하지 않고 테스트하기 어렵다.
public class SpellChecker {
private final Lexicon dictionary ...;
private SpellChekcer(...) {}
public static SpellChecker INSTANCE = new SpellCHecker(...); // 싱글턴 자원
public boolean isValid(String word) { ... }
public List<String> suggestions(String typo) { ... }
두 방법 모두 다른 종류의 dictionary가 필요한 경우 대응하기가 힘들다.
만약 다른 종류의 사전을 이용한 speccChecker가 필요한 경우 해당 클래스를 찾아가서 내부 의존 dictionary를 변경해주어야함!
개선
의존성 주입
자원을 단 하나만 사용한다는 것은 훌륭하지 않음. => 향후 확대도 고려해서 유연한 구조로 만들자!
사용하는 자원에 따라 동작이 달라지는 클래스에는 적정 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.
인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식
코드 5-3 의존성 객체 주입은 유연성과 테스트 용이성을 높여준다.
public class SpellChecker {
private final Lexicon dictionary ...;
public SpellChekcer(Lexicon dictionary) { // 생성된 자원
this.dictionary = Objects.requireNonNul(dictionary);
}
public static boolean isValid(String word) { ... }
public static List<String> suggestions(String typo) { ... }
장점
불변(#17) 보장 -> 생성자이기에 객체를 한번 생성하면 내부 setter가 없는 이상 변경 불가능
static class Mosaic {
Mosaic(Tile tile) {
System.out.println("I'm a Mosaic with " + tile.tileName());
}
}
Mosaic create(Supplier<? extends Tile> tileFactory) {
// factory 를 받은 만큼 몇번이고 생성해도 상관없다. 생성자를 변경하지 않아도, 원하는 tile에 따라 생성해준다!
return new Mosaic(tileFactory.get());
}
@Test
public void test() {
// 원하는 tile을 넣어 생성할 수 있다!
Mosaic result = create(() -> new StoneTile("RED"));
}
}
자원을 사용하는 방식
정적 유틸리티 클래스 (#4)
코드 5-1 정적 유틸리티를 잘못 사용한 예 - 유연하지 않고 테스트하기 어렵다.
싱클턴 (#3)
코드 5-2 싱글턴을 잘못 하용한 예 - 유연하지 않고 테스트하기 어렵다.
개선
의존성 주입
코드 5-3 의존성 객체 주입은 유연성과 테스트 용이성을 높여준다.
장점
발전(변형)
생성자에 자원 팩터리 전달
자바8의 Supplier 인터페이스 (#31) (https://codechacha.com/ko/java8-supplier-example/)
static class CeramicTile extends Tile { CeramicTile(String color) { super(color); } }
static class StoneTile extends Tile { StoneTile(String color) { super(color); } }
static class Mosaic { Mosaic(Tile tile) { System.out.println("I'm a Mosaic with " + tile.tileName()); } }
Mosaic create(Supplier<? extends Tile> tileFactory) { // factory 를 받은 만큼 몇번이고 생성해도 상관없다. 생성자를 변경하지 않아도, 원하는 tile에 따라 생성해준다! return new Mosaic(tileFactory.get()); }
@Test public void test() { // 원하는 tile을 넣어 생성할 수 있다! Mosaic result = create(() -> new StoneTile("RED")); } }
단점