skip to content
Q

[Effective Jave 3/e] Item5 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

/ 3 min read

Table of Contents

유연하지 않은 객체

정적 유틸리티 클래스

public class SpellChecker {
private static final Lexicon dictionary = ...;
private SpellChecker() {}
public static boolean isValid(String word) {...}
public static List<String> suggestions(String typo) {...}
}

싱글턴

public class SpellChecker {
private final Lexicon dictionary = ...;
private SpellChecker(...) {}
public static SpellChecker INSTANCE = new SpellChecker(...);
public boolean isValid(String word) {...}
public List<String> suggestions(String typo) {...}
}

위 두가지 방식의 클래스들은 dictionary이 하나로 고정되어 있다. 코드 자체를 변경하지 않는 한 dictionary를 변경할 수 없다.

클래스 내에 changeDictionary같은 메서드를 만들어 사용할 수도 있으나 fianl키워드를 빼야해 동시성 혹은 다른 곳에서 에러날 수 있다.

이러한 문제들은 의존 객체 주입(Dependency Injection)을 활용해 해결 가능하다. 인스턴스 생성시 생성자에 필요한 자원을 넘겨주는 방식이다.

public class SpellChecker {
private final Lexicon dictionary = ...;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
public boolean isValid(String word) {...}
public List<String> suggestions(String typo) {...}
}

이렇게 되면 좀더 유연하고 테스트 용이하게 해줄 뿐 아니라, 빌터, 정적 팩터리 패턴에서 동일하게 응용 가능하다.

심지어 java8의 Supplier<T>를 활용해 팩터리를 넘기는 것이 가능하다. 이는 팩터리 메서드 패턴(Factory Method pattern)이다.

와일드 카드를 활용해 해당 타입의 하위 타입이라면 만들 수 있는 팩터리 메서드를 인자로 줄 수 있다.

public create(Supplier<? extends Car> carFactory) {}

의존성 주입이 많아지면 프로젝트가 많이 복잡해져 코드를 보기 어려워진다. 이는 의존 객체 주입 프레임워크(e.g. Spring)을 활용해 해소 가능하다.

Summary

클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 싱글턴, 정적 유틸리티 클래스 사용하지 않는 것이 좋다. 이 자원을 클래스가 직접 만들게 해서도 안된다. 의존 객체 주입으로 자원을 넘겨주자. 클래스의 유연성, 재사용성 테스트 용이성을 개선해준다. {: .prompt-tip }