[아이템 5] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

Jimin Lim·2022년 2월 27일
0

Effective Java

목록 보기
5/38
post-thumbnail

아이템 5

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

많은 클래스가 하나 이상의 자원에 의존한다. 예를 들어 맞춤법 검사기 SpellChecker 클래스가 사전 dictionary 에 의존하는 경우가 있다면, 이 방식을 (1) 정적 유틸리티 클래스(2) 싱글턴 방식으로 사용할 수 있다.

(1) 정적 유틸리티 클래스

public class SpellChecker {
	private static final Lexicon dictionary = ...; 
	private SpellChecker() {} // 객체 생성 방지 

	public static boolean isValid(String word) { ... } 
	public static List<String> suggestions(String typo) { ... } 
}

(2) 싱글턴 방식

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

SpellChecker 라는 클래스를 생성할 때, dictionary를 수정할 수 없기에 유연하지 않고 테스트하기에도 어렵다. 만약 다른 사전으로 변경할 때 필드에서 final 한정자를 제거하고 다른 사전으로 교체하는 메서드(setter)를 추가할 수 있지만, 이 방식은 오류를 낼 수 있으며 멀티스레드 환경에서 적합하지 않다.

즉, 사용하는 자원에 따라 동작이 달라지는 클래스는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다. 따라서 이를 해결하기 위해 아래와 같이 의존 객체 주입 방식을 사용하는 방식을 사용할 수 있다.

의존 객체 주입 방식

public class SpellChecker { 
	private final Lexicon dictionary; 

	private SpellChecker(Lexicon dictionary) { 
    		this.dictionary = Objects.requireNonNull(dictionary); 
 	} 

	public boolean isValid(String word) { return true; } 
	public List<String> suggestions(String typo) { return null; } 
}

의존 객체 주입은 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이다. 따라서 클래스가 여러 자원 인스턴스를 지원할 수 있고, 클라이언트가 원하는 자원을 사용할 수 있게 해준다.

변형으로 생성자에 자원 팩터리를 넘겨주는 방식이 있다. 여기서 팩터리란 호출할 때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체를 말한다. Supplier<T>를 이용해서 자신이 명시한 타입의 하위 타입이라면 무엇이든 생성할 수 있는 팩터리를 넘길 수 있다.

public class SpellChecker { 
	private final Lexicon dictionary; 

	private SpellChecker(Supplier<? extends Lexicon> dictionary) { 
    		this.dictionary = dictionary.get();
 	} 
    ...
}

의존성이 수천 개나 되는 큰 프로젝트에서는 코드를 어지럽게 만들기에 Dagger, Guice, Spring 과 같은 의존 객체 주입 프레임워크를 사용하도록 한다.

profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글