[이펙티브 자바] 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

노을·2023년 1월 18일
0

이펙티브 자바

목록 보기
5/14
post-thumbnail
public class SpellChecker {

    private Dictionary dictionary = new Dictionary();
    
    public static boolean isValid(String word) {
        ...
        return dictionary.contains(word);
    }

}

SpellChecker라는 클래스에서 Dictionary 객체가 사용되는 상황을 생각해보자.
그런데 SpellChecker에서 언어별로 사전이 따로 있을 수도 있고, 특수 어휘용 사전을 별도로 두는 상황이 있을 수 있다. 이런 식으로 자원을 명시 (new로 생성)하면 어떤 단점이 있을까?

⭐ 사용하는 자원에 따라 동작이 달라지는 클래스에 자원을 명시했을 때

☑️ 유연하지 않다.

public class SpellChecker {

    private Dictionary dictionary = new KoreanDictionary();
    
    public static boolean isValid(String word) {
        ...
        return dictionary.contains(word);
    }

}

KoreanDictionary 객체로 바꾸고 싶다면 SpellChecker의 코드를 수정해야 한다. (OCP 법칙 위배)

☑️ 테스트하기 어렵다.

SpellChecker를 테스트할 때 당연하게도 SpellChecker가 명시한 Dictionary 객체를 사용해야 한다.
1. Dictionary가 아닌 다른 자원을 쓰고 싶을 때도 별 다른 방법이 없다.
2. Dictionary 객체 생성 비용이 큰 경우라면? Dictionary 객체를 생성하지 않고 테스트해도 괜찮은 경우에도 Dictionary를 사용할 수 밖에 없다. (의미 없는 객체 생성 비용 발생)

⭐ 의존 객체 주입 방식을 사용하자.

인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주면 된다.
(이때 Dictionary라는 인터페이스를 만들어 구현체를 주입 받는다.)

public class SpellChecker {

    private final Dictionary dictionary;

    public SpellChecker(Dictionary dictionary) {
        this.dictionary = dictionary;
    }

    public boolean isValid(String word) {
        ...
    }

    public List<String> suggestions(String typo) {
		...
    }
}

이렇게 생성자로 객체를 주입 받게되면 SpellChecker 객체 생성 시에 생성자가 딱 한 번 호출되는 것을 보장한다.
참고로 의존 객체 주입에는 생성자 주입, 필드 주입, Setter 주입, 일반 메서드 주입이 있는데 이에 관한 것 [Spring] DI를 하는 여러가지 방법을 참고하자!

☑️ SpellChecker 테스트 코드

@Test
void isValid() {
    SpellChecker spellChecker = new SpellChecker(new KoreanDictionary);
    spellChecker.isValid("test");
}

의존 객체 주입을 받으면 다음과 같이 코드를 사용하는 클라이언트 입장에서 객체를 설정할 수 있게 된다.

☑️ 다양한 객체 사용

또한 SpellChecker 내부에는 구현체 코드가 없기 때문에, 나중에 구현체를 바꾸게 되어도 SpellChecker 코드 변경은 일어나지 않는다. (유연한 설계)

⭐ 생성자에 자원 팩터리를 넘겨주는 방식

의존 객체 주입 방식의 변형으로 생성자에 자원 팩터리를 넘겨주는 방식이 있다.

0개의 댓글