HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🛁
공부기록
/
📚
책 정리
/
🚐
item5 - 리소스를 엮을 때는 의존성 주입을 선호하라
🚐

item5 - 리소스를 엮을 때는 의존성 주입을 선호하라

속성
2장

리소스를 엮을 때는 의존성 주입을 선호하라

  • 대부분의 클래스는 여러 리소스에 의존하게 된다.
  • 이 책에서는 SpellChecker / Dictionary를 예로 들고있다.
  • 즉 SpellCheck가 Dictionary를 사용하고 이를 의존하는 리소스 또는 의존성 이라고 부른다.
  • 이때 SpellChecker를 다음과 같이 구현하는 경우가 있다.

싱글톤으로 구현하기

  • 사전을 하나만 사용할거라면 위와 같은 구현도 만족스러울 수 있겠지만 실제로는 각 언어의 맞춤법 검사기는 사용하는 사전이 각기 다르다.
  • 또한 테스트코드에서는 테스트용 사전을 사용하고 싶을 수도 있다.
  • 어떤 클래스가 사용하는 리소스에 따라 활동을 달리 해야하는 경우에는 스테틱 유틸리티 클래스와 싱글톤을 사용하는 것은 적절하지 못하다.
  • 그런 요구사항을 만족시킬 수 있는 간단한 패턴으로 생성자를 사용해서 새 인스턴스를 생성할 때 사용할 리소스를 넘겨주는 방식이 있다.

적절한 구현

  • 위와 같은 의존성 주입은 생성자, 스테틱 팩토리 그리고 빌더에도 적용할 수 있다.
  • 이 패턴의 변종으로 리소스의 팩토리를 생성자에 전달하는 방법도 있다. 이 방법은 자바 8에 들어온 Supplier
    • 인터페이스가 그런 팩토리로 쓰기에 완벽하다.
  • Supplier를 인자로 받는 메서드는 보통 bounded wildcard type으로 입력을 제한해야 한다. > Mosaic create(Supplier extends Tile) tileFactory) { … }
  • 의존성 주입이 유연함과 테스트 용이함을 크게 향상시켜 주지만 의존성이 많은 큰 프로젝트인 경우에는 코드가 장황해 질 수 있다.
  • 그점은 대거, 쥬스, 스프링같은 프레임웤을 사용해서 해결할 수 있다.

요약

  • 의존하는 리소스에 따라 행동을 달리하는 클래스를 만들 때는 싱글톤이나 스테틱 유틸 클래스를 사용하지 말자. 그런 경우에는 리소스를 생성자나 팩토리로 전달하는 의존성 주입을 사용하여 유연함, 재사용성, 테스트 용이성을 향상시키자.
public class SpellChecker { // 바꿔끼기가 힘들다. 테스트도 힘들다. private static final Lexicon dictionary = new KoreanDictionary(); private SpellChecker() { // Noninstantiable } public static boolean isValid(String word) { throw new UnsupportedOperationException(); } public static List<String> suggestions(String type) { throw new UnsupportedOperationException(); } public static void main(String[] args) { SpellChecker.isValid("hello"); } } interface Lexicon{} class KoreanDictionary implements Lexicon { }
public class SpellChecker { private final Lexicon dictionary = new KoreanDictionary(); private SpellChecker() { } public static final SpellChecker INSTANCE = new SpellChecker(){}; public boolean isValid(String word) { throw new UnsupportedOperationException(); } public List<String> suggestions(String type) { throw new UnsupportedOperationException(); } // 싱글톤 인스턴스를 통해서 사용한다. public static void main(String[] args) { SpellChecker.INSTANCE.isValid("hello"); } } interface Lexicon{} class KoreanDictionary implements Lexicon { }
public class SpellChecker { private final Lexicon dictionary; public SpellChecker(Lexicon dictionary) { this.dictionary = Objects.requireNonNull(dictionary); ; } public boolean isValid(String word) { throw new UnsupportedOperationException(); } public List<String> suggestions(String type) { throw new UnsupportedOperationException(); } public static void main(String[] args) { Lexicon lexicon = new KoreanDictionary(); SpellChecker spellChecker = new SpellChecker(lexicon); spellChecker.isValid("hello"); } } interface Lexicon { } class KoreanDictionary implements Lexicon { }