Home Item 5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
Post
Cancel

Item 5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

많은 클래스는 하나 이상의 자원에 의존한다. 이 책에서는 맞춤법 검사기인 SpellCheckerdictionary를 예로 들고있다. 즉, SpellCheckerdictionary를 사용하고, 이를 의존 하는 리소스 또는 의존성이라고 부른다. 이때 SpellChecker를 다음과 같이 구현하는 경우가 있다.

부적절한 구현

static 유틸 클래스

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
public class SpellChecker {

    //한국 사전으로 고정되어있음
    private static final Lexicon dictionary = new KoreanDictionary();

    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("hello");
    }
}

interface Lexicon{}

class KoreanDictionary implements Lexicon{}

위소스 내 모든 유틸리티 메소드는 public한 static으로 만들어져 있다. 이 메소드들에서 dictionary을 참조해야 하므로 생성자도 static 타입으로 생성해야 한다. 생성자는 new koreanDictionary()을 통해 만들어 final로 지정했기 때문에 고정이 되어 변경하기가 힘들다.

SpellChecker 클래스를 테스트 할 때도 dictionary까지 테스트하게된다. 이렇게 되면 유연하지 않고 테스트하기 어렵다는 단점이 있다.

싱글턴 클래스(정적 팩터리 방식)

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
public class SpellChecker {

    //한국 사전으로 고정되어있음
    private final Lexicon dictionary = new KoreanDictionary();

    private SpellChecker(){
        // 객체생성방지
    }

    public static final SpellChecker INSTANCE = new 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.INSTANCE.isValid("hello");
    }
}

interface Lexicon{}

class KoreanDictionary implements Lexicon{}

사전을 하나만 사용할거라면 위와 같은 구현도 만족스러울 수 있겠지만, 실제로는 각 언어의 맞춤법 검사기는 사용하는 사전이 각기 다르다. 또한 테스트 코드에서는 테스트용 사전을 사용하고 싶을 수도 있다.

위 소스코드가 부적절하고 유연하지 않은 이유는 언어가 바뀌면 위 소스코드에서 new KoreanDictionary()이 부분이 바뀌어야 하기 때문이다.

어떤 클래스가 사용하는 자원에 따라 동작이 달라지는 클래스에는 스태틱 유틸리티 클래스와 싱글톤을 사용하는 것은 부적절하다.

이런 경우 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이 낫다. 이는 의존 객체 주입의 한 형태로, 맞춤법 검사기를 생성할 때 의존객체인 사전을 주입해주면 된다.

적절한 구현

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
public class SpellChecker {

    private Lexicon dictionary;

    //생성자에 의존객체인 사전을 주입
    public SpellChecker(Lexicon dictionary){
        this.dictionary = Objects.requireNonNull(dictionary);
    };

    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) {

    }
}

interface Lexicon{}

class KoreanDictionary implements Lexicon{}
This post is written by PRO.