Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- select_type
- 조합
- SQL
- MSA
- java
- 바이너리 카운팅
- stream
- AOP
- DI
- Test
- Spring
- hashcode
- cache
- 인덱스
- jwt
- 테스트 코드
- KEVISS
- 열 속성
- StringBuilder
- 재정의
- VUE
- 생성자 주입
- DDL
- 필드 주입
- lambda
- jpa
- docker
- static
- equals
- redis
Archives
- Today
- Total
백엔드 개발자 블로그
[Effective Java] Item5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 본문
정적 유틸리티와 싱글턴의 단점
대부분의 많은 클래스들은 하나의 자원에 의존합니다.
// 정적 유틸리티를 잘못 사용한 예
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 getInstance() = new SpellChecker(..);
public boolean isValid(String word) {...}
public List<String> suggestions(String typo) {...}
}
위의 두 코드는 사전을 정적 유틸리티와 싱글턴을 통해 구현한 각각의 코드입니다. 작업이 다양한 경우(언어별, 특수 어휘용 등으로 분류 가능)에는 하나의 사전에서 모든 일을 하는 것을 효율적이지 않습니다.
의존 객체 주입 패턴
이와 같이 사용하는 자원에 따라 동작이 달라지는 클래스들은 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않습니다.
이러한 경우에는 클래스가 단일 인스턴스가 아닌 여러 인스턴스를 지원하고 사용자 입장에서 원하는 자원을 사용할 수 있도록 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식을 사용해야 합니다. (의존 객체 주입의 한 형태)
// 의존 객체 주입을 한 예
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) {...}
}
위의 코드는 의존 객체 주입을 한 예시 코드입니다. 코드를 보면 위의 싱글턴과 정적 유틸리티 클래스를 통한 공통된 메서드 사용이 아닌 생성자에 원하는 자원(dictionary)를 넘겨주며 원하는 인스턴스를 만들고 그에 맞는 자원을 쓸 수 있습니다.
이러한 생성자 주입은 정적 팩터리와 빌더에도 모두 응용 가능하다.
팩터리 메서드 패턴
의존 객체 주입 패턴의 변형으로 생성자에게 자원 팩터리를 넘겨주는 팩터리 메서드 패턴(Factory Method Pattern)이 있습니다.
@FunctionalInterface
public interface Supplier<T> {
T get();
}
다음 인터페이스를 예시로 들자면 Supplier<T>는 <T>를 통해 타입 매개변수를 제한하고, 클라이언트는 제한한 타입의 하위 타입이라면 무엇이든 생성할 수 있는 팩터리를 넘길 수 있습니다.
팩터리란? 호출될 때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체
의존 객체 주입의 장단점
장점
- 유연성, 재사용성, 테스트 용이성을 개선해줍니다.
단점
- 의존성이 많은 큰 프로젝트에서는 코드를 어지럽게 만들기도 합니다.
- 스프링(Spring), 대거(Dagger)와 같은 의존 객체 주입 프레임워크는 의존 객체를 직접 주입하도록 설계된 API를 사용하여 개발자의 불편함을 감소시켜줄 수 있습니다.
핵심 정리
- 싱글턴과 정적 유틸리티 클래스는 사용하면 안되는 상황
- 클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다.
- 이 자원들은 클래스가 직접 만들게 해서도 안 된다.
- 해결책
- 의존 객체 주입(필요한 자원을 생성자 or 정적 팩터리나 빌더에 넘겨주는 것)
- 효과
- 클래스의 유연성, 재사용성, 테스트 용이성을 개선해준다.
- 주의점
- 의존성이 많은 큰 프로젝트에서는 코드를 어지럽게 만들수도 있으니 스프링(Spring), 대거(Dagger)와 같은 의존 객체 주입 프레임워크를 사용하여 개선하자.
'Java' 카테고리의 다른 글
[Effective Java] Item7. 다 쓴 객체 참조를 해체하라 (0) | 2024.03.22 |
---|---|
[Effective Java] Item6. 불필요한 객체 생성을 피하라 (0) | 2024.03.22 |
[Effective Java] Item4. 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2024.03.21 |
[Effective Java] Item3. private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2024.03.20 |
[Effective Java] Item2. 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2024.03.19 |