사용하는 자원에 따라 동작이 달라지는 클래스는 앞서 다루었던 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않습니다.
이러한 클래스는 Spring Framework를 공부했다면 지겹게 들었을 의존성 주입(Dependency Injection)이 적합합니다.
사용하는 자원에 따라 동작이 달라지는 클래스
책에서 예시로 든 맞춤법 검사기는 사전에 의존하는데 한영사전이냐 영한사전이냐에 따라 SpellChecker 클래스의 동작이 달라질 것입니다.
- 한영사전은 isValid() 메서드를 통해 한글 단어가 존재하는지 확인할 것이고 suggestions() 메서드를 통해 오타가 났을 때 가장 근접한 한글 단어를 추천
- 반면 영한사전은 isValid() 메서드를 통해 영어 단어가 존재하는지 확인할 것이고 suggestions() 메서드를 통해 오타가 났을 때 가장 근접한 영어 단어를 추천
정적 유틸리티 클래스가 적합하지 않은 이유
사전 클래스를 정적 유틸리티 클래스로 사용하면 곤란한 이유는 아래와 같습니다.
- 사전에 따라 동작이 달라질 수 있는데 정적 유틸리티 클래스를 사용할 경우 사전을 변경할 수 없음
- dictionary 인스턴스를 생성하는데 cpu도 많이 쓰고 메모리도 많이 쓴다고 가정했을 때 사전을 변경할 때마다 인스턴스를 생성하는 것은 매우 비싼 작업
- 테스트할 때마다 dictionary 인스턴스를 무조건 생성하는 것도 문제
정리하자면 정적 유틸리티 클래스의 경우 자원을 직접 명시했기 때문에 유연하지 않고 테스트 코드 작성하기 힘듭니다.
따라서 사용하는 자원에 따라 동작이 달라지는 클래스에는 적합하지 않은 구조입니다.
싱글톤 방식이 적합하지 않은 이유
싱글턴 방식 또한 정적 유틸리티 클래스와 동일한 문제점이 존재합니다.
- dictionary 인스턴스 없이는 테스트 불가
- 굳이 mocking을 한다면 할 수 있겠지만 권장하는 방법 아님
- 한영사전, 영한사전에 따라 각각 다르게 테스트하고 싶을 때도 아래와 같은 방법으로 진행해야 하고 이는 유연성이 떨어지고 재사용성이 떨어지는 문제점이 존재합니다.
- dictionary에 각각 다른 사전을 넣어주거나
- SpellChecker 클래스를 상속하는 서브 클래스에서 KoreanEnglishDictionary 혹은 EnglishKoreanDictionary를 넣어줌
의존성 주입이 적합한 이유
의존성 주입을 사용할 경우 사전을 직접 명시하는 것이 아니기 때문에 dictionary가 바뀐다고 해도 모든 코드를 재사용 가능합니다.
- 단, 이 때 전제조건은 dictionary가 interface라는 가정
- Dictionary가 클래스일 경우 규약이 없기 때문에 KoreanEnglishDictionary와 EnglishKoreanDictionary가 각각 다른 메서드를 가질 수 있기 때문에 인터페이스여야 함
의존성 주입을 사용할 경우 SpellChecker의 외부에서 SpellChecker 가 사용하는 리소스를 주입해 줄 수 있기 때문에 테스트 코드 작성 시 여러 Dictionary를 주입 가능해지고 이에 따라 코드 재사용성을 높일 수 있습니다.
해당 패턴의 쓸만한 변형으로 생성자에 자원 팩토리를 넘겨주는 방식도 있습니다.
- 앞서 아이템 3에서 간단히 언급한 Supplier 인터페이스가 대표적인 팩토리 메서드 패턴
자원 팩토리를 넘겨주는 방식은 팩토리를 넘겨받는 클라이언트 코드의 변경이 전혀 필요없기 때문에 확장에는 열려있고 변경에는 닫혀 있다는 장점이 있습니다. (OCP 원칙)
정리
클래스가 내부적으로 하나 이상의 자원에 의존하고 해당 자원이 클래스 동작에 영향을 준다면 명시적으로 자원을 지정하는 정적 유틸리티 클래스 혹은 싱글톤 방식을 사용하는 것은 지양해야 합니다.
대신 필요한 자원을 생성자에 넘겨주는 DI를 사용할 경우 코드 유연성, 재사용성, 그리고 테스트 용이성을 챙길 수 있습니다.
참고
이펙티브 자바
이펙티브 자바 완벽 공략 1부 - 백기선 강사님
'JAVA > Effective Java' 카테고리의 다른 글
[아이템 7] 다 쓴 객체 참조를 해제하라 (0) | 2024.01.22 |
---|---|
[아이템 6] 불필요한 객체 생성을 피하라 (0) | 2024.01.21 |
[아이템 4] 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2024.01.20 |
[아이템 3] private 생성자나 열거 타입으로 싱글턴임을 보증하라 (2) | 2024.01.19 |
[아이템 2] 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2024.01.18 |