이 포스팅에서 작성하는 내용은 EFFECTIVE JAVA(이펙티브자바) 에서 발췌하였습니다.
아이템 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
클래스에서 하나 이상의 자원에 의존을 할 때, 이를 구현하는 방법 중 잘못된 예가 있다.
SpellChecker 라는 클래스가 사전에 의존한다고 가정해보자.
1) 정적 유틸리티를 잘못 사용
public class SpellChecker {
private static final Lexicon dictionary = ...; // 의존 대상(사전)
private SpellChecker() { } // private 생성자를 정의함으로써 객체 생성 방지
...
}
2) 싱글톤을 잘못 사용
public class SpellChecker {
private final Lexicon dictinary = ...;
private SpellChecker(...) { }
public static SpellChecker INSTANCE = new SpellChecker(...);
...
}
위의 방식 모두 사전을 여러 개를 사용한다는 가정을 하면 훌륭하지 않다.
언어마다 사전이 다를 수 있고 테스트용 사전이 필요할 수 있기 때문이다.
즉, 사용하는 자원에 따라 동작이 달라지는 클래스는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.
클래스가 여러 자원 인스턴스를 지원해야하며, 클라이언트가 원하는 자원을 사용해야할 때 아래의 방식을 사용하면 된다.
* 의존 객체 주입 방식
- 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식
- 유연성과 테스트 용이성을 개선
- 불변을 보장하여(변경될 일이 없음) 같은 자원을 사용하려는 여러 클라이언트가 의존 객체를 안심하고 공유
- 의존 객체를 주입하는 방식은 생성자, 정적 팩터리 메소드, 빌더에 똑같이 응용 가능
- 의존성이 상당히 많은 큰 프로젝트에서는 코드를 복잡하게 만들기 때문에 의존 객체 주입 프레임워크(ex. Spring) 을 사용하면 좋다.
public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
...
}
+ 팩터리 메서드 패턴(Factory Method Pattern)
위의 변형으로 생성자에 자원 팩터리를 넘겨주는 방식이 존재.
팩터리란? 호출할 때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체를 의미함
Supplier<T> Interface : 팩터리를 표현한 완벽한 예
- Supplier<T>를 입력으로 받는 메서드는 일반적으로 한정적 와일드카드 타입을 사용해 팩터리의 타입 매개변수를 제한해야함
- 이 방식을 이용해 클라이언트는 자신이 명시한 타입의 하위 타입을 생성할 수 있는 팩터리를 넘길 수 있음
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get(); // 매개변수가 없고 T를 반환하는 추상 메서드
}
ex) 클라이언트가 제공한 팩터리가 생성한 타일(Tile)들로 구성된 모자이크(Mosaic)를 만드는 메서드
Mosaic create(Supplier<? extneds Tile> tileFactory { ... }
정리
클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 싱글톤과 정적 유틸리티 클래스는 사용하지 않는 것이 좋음.
의존 자원들은 클래스가 직접 만들게 해서는 안되며, 대신 필요한 자원을 생성자, 정적 팩터리 메서드, 빌더에 넘겨줘야 한다.
'BE > Java' 카테고리의 다른 글
[Effective Java] 아이템 7. 다 쓴 객체 참조를 해제하라 (0) | 2022.09.05 |
---|---|
[Effective Java] 아이템 6. 불필요한 객체 생성을 피하라 (0) | 2022.09.02 |
[Effective Java] 아이템 4. 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2022.08.31 |
[Effective Java] 아이템 3. private 생성자나 열거 타입으로 싱글턴임을 보장하라. (0) | 2022.08.31 |
[Effective Java] 아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라. (0) | 2022.08.30 |