본문 바로가기

IT/자바

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

반응형

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

 

사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.

 

예를 들어 스펠링 검사 클래스를 구현할때 사전이라는 객체는 불변의 객체로 공유되어야 한다.

하지만, 이때 사전은 언어별로 또는 특수 어휘용으로 검사의 기준이 되는 사전은 달라질 수 있다. 

 

정적 유틸리티

public class SpellChecker {
    private static final Lexicon dictionary = ...;

    private SpellChecker() {
    }
    ...
}

싱클턴 패턴

public class SpellChecker {
    private static final Lexicon dictionary = ...;

    private SpellChecker() {
    }

    public static SpellChecker INSTANCE = new SpellChecker();
    ...
}

그러므로 이런 경우 유틸리티 클래스지만, 사전이라는 객체를 정적 유틸과 싱클턴으로 구현해서는 안된다.

 

위 코드에서 단순히 final만 제거할 경우 코드상으로 어색하며 멀티 스레드 환경에서는 사용할 수가 없게 된다.

 

그럼 클라이언트가 필요한 사전에 대한 처리를 어떻게 할 것인가?

public class SpellChecker {
    private final Lexicon dictionary;
    
    // 여기서 의존성 주입을!
    public SpellChecker(Lexicon dictionary){
    	this.dictionary = Objects.requireNotNull(dictionary);
    }
    
    public static boolean isVaild(String word) {...}
    public static List<String> suggestions(String typo) {...}
}

// 인터페이스
interface Lexicon {}

// Lexicon을 상속 받아서 구현
public class myDictionary implements Lexicon {
	...
}

// 사용은 이렇게!
Lexicon dic = new myDictionary();
SpellChecker chk = new SpellChecker(dic);

chk.isVaild(word);

인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 "의존 객체 주입"으로 해결할 수 있다.

 

또한, Supplier<T> 인터페이스를 사용해서 팩터리 메서드 패턴으로 호출할 때마다 특정 타입의 인스턴스를 생성해 줄 수 있다.

Mosaic create(Supplier<? extends Tile> tileFactory> {... }

정리

클래스가 내부적으로 하나 이상의 자원에 의존하고, 그자원이 클래스 동작에 영향을 준다면 싱글턴과 정적 유틸리티 클래스는 사용하지 않는 것이 좋다. 

의존 객체 주입을 사용하면 클래스의 유연성, 재사용성, 테스트 용이성 등을 개선시킨다.

 

반응형