이펙티브 자바
아이템 5. 자원을 직접 명시 하지 말고 의존성 객체 주입(dependency injection)을 사용하라
지금 대부분 자바 개발자들은 spring 프레임워크를 쓰면서 의존성 주입에 대한 이견은 없을 것입니다.
| 12
 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 {
 }
 
 
 | 
위에 방식으로 구현한 케이스와 비슷하게 아래 처럼 싱글턴방식으로 구현한 케이스 두가지는 흔한 방식이다.
| 12
 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 커플링 된 상태이다. 
커플링된 코드를 디커플링 시키기 위해서 의존성 주입을 선택할수도 있다.
그럼 코드를 바꾸면 
| 12
 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가 적용되면서 이렇게 비슷하게 디커플링 시킬수 있다.
이렇게 언어 차원에서도 할수 있지만 프로젝트가 커지고 하면 프레임워크 도입도 고려 해봐야 된다.
참조