이펙티브 자바
아이템 5. 자원을 직접 명시 하지 말고 의존성 객체 주입(dependency injection)을 사용하라
지금 대부분 자바 개발자들은 spring 프레임워크를 쓰면서 의존성 주입에 대한 이견은 없을 것입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.github.sejoung.codetest.di.test1;
import java.util.List;
public class SpellChecker { private static final Lexicon dictionary = new KoreanDicationry();
private SpellChecker() { }
public static boolean isValid(String word) { throw new UnsupportedOperationException(); }
public static List<String> suggestions(String typo) { throw new UnsupportedOperationException(); }
public static void main(String[] args) { SpellChecker.isValid("하이"); } }
interface Lexicon { }
class KoreanDicationry implements Lexicon { }
|
위에 방식으로 구현한 케이스와 비슷하게 아래 처럼 싱글턴방식으로 구현한 케이스 두가지는 흔한 방식이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.github.sejoung.codetest.di.test2;
import java.util.List;
public class SpellChecker {
private final Lexicon dictionary = new KoreanDicationry();
private SpellChecker() { }
public static final SpellChecker INSTANCE = new SpellChecker() { };
public boolean isValid(String word) { throw new UnsupportedOperationException(); }
public List<String> suggestions(String typo) { throw new UnsupportedOperationException(); }
public static void main(String[] args) { SpellChecker.INSTANCE.isValid("하이"); }
}
interface Lexicon {}
class KoreanDicationry implements Lexicon {}
|
위에 2가지 방식다 모두 단하나의 사전만 사용한다는 점에서 그리 훌륭해 보이지 않다.
위에 코드는 SpellChecker 클래스와 KoreanDicationry 커플링 된 상태이다.
커플링된 코드를 디커플링 시키기 위해서 의존성 주입을 선택할수도 있다.
그럼 코드를 바꾸면
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package com.github.sejoung.codetest.di.test3;
import java.util.List; import java.util.Objects; import java.util.function.Supplier;
public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Supplier<Lexicon> dictionary) { this.dictionary = Objects.requireNonNull(dictionary.get()); }
public boolean isValid(String word) { throw new UnsupportedOperationException(); }
public List<String> suggestions(String typo) { throw new UnsupportedOperationException(); }
public static void main(String[] args) { Lexicon lexicon = new TestDictionary(); SpellChecker spellChecker = new SpellChecker(() -> lexicon); spellChecker.isValid("하이"); }
}
interface Lexicon {}
class KoreanDictionary implements Lexicon {}
class TestDictionary implements Lexicon {}
|
위에 처럼 SpellChecker 생성시에 주입을 선택하면 생성시에 언제든 사전을 교체 할 수 있다.
그럼 SpellChecker 에서 기존에 KoreanDictionary와 가지고 있던 커플링이 디커플링 된다.
이런 비슷한 일을 java 6부터 service loader에서 비슷하게 할수 있고
또 java 9 부터 jigsaw가 적용되면서 이렇게 비슷하게 디커플링 시킬수 있다.
이렇게 언어 차원에서도 할수 있지만 프로젝트가 커지고 하면 프레임워크 도입도 고려 해봐야 된다.
참조