Java/이펙티브 자바(Effective Java)

[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

얄루몬 2022. 4. 8. 18:01

📖본 포스팅은 'Effective java - 조슈아' 님의 책를 보고 작성되었습니다.


[하나 이상의 자원에 의존한 클래스 - 잘못된 예시들]

  • 많은 클래스가 하나 이상의 자원에 의존한다. 
  • 아래는 자원에 의존한 클래스들의 잘못된 예시들이다.

[정적 유틸리티를 잘못 사용한 예 - 유연하지 않고 테스트하기가 어렵다.]

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

    //객체 생성 방지 -> 정적 유틸리티는 객체 생성을 원하지 않기에 이를 private 생성자로 방지해주어야 한다. 
    private SpellChecker(){}
    
    public static boolean isValid(String word){ ... }
    public static List<String> suggestions(String typo) {...}
    
}

[싱글턴을 잘못 사용한 예 - 유연하지 않고 테스트하기가 어렵다.]

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

    private SpellChecker(){}
    public static SpellChecker INSTANCE = new SpellChecker(...);
    
    public static boolean isValid(String word){ ... }
    public static List<String> suggestions(String typo) {...}
    
}
  • 위의 두개의 코드 모두 하나의 사전만 사용한다고 가정했다는 점에서 그리 훌륭한 코드가 아니라고 보인다.
  • 실전에서는 사전이 언어별로 있고 특수 어휘용 사전도 별도로 두기 때문에 사전 하나로 모든 쓰임에 대응할 수 없기에 매우 좋지 않은 코드라고 할 수 있다.

 

[의존 객체 주입 = 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방법]

public class SpellChecker{
    private final Lexicon dictionary;

    public SpellChecker(Lexicon dictionary){
        this.dictionary = Objects.requireNonNull(dictionary);
    }
    public static boolean isValid(String word){ ... }
    public static List<String> suggestions(String typo) {...}

}
  • 사용하는 자원에 따라 동작이 달라지는 클래스는 정적 유틸리티 클래스나 싱글턴 방식은 적합하지 않다.
  • 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식 = 의존 객체 주입
    • 대신 클래스가 여러 자원 인스턴스를 지원해야 한다.
    • 클라이언트가 원하는 자원(dictionary)을 사용해야 한다.

[의존 객체 주입의 장점]

  • 불변을 보장한다.
  • 같은 자원을 사용하려는 여러 클라이언트가 의존 객체를 안심하고 공유할 수 있다.
  • 의존 객체의 주입은 생성자, 정적 팩터리, 빌더 모두에 똑같이 응용 가능하다.
  • 의존 객체 주입은 유연성과 테스트 용이성을 개선해준다.

[의존 객체 주입의 단점]

  • 코드가 수천 개나 되는 큰 프로젝트에서는 코드를 어지럽게 만든다. 
    • 그러나 이는 주스(Guice), 스프링(Spring) 같은 의존 객체 주입 프레임워크를 사용하면 해결할 수 있다. 

 

[정리]

  • 클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 싱글턴과 정적 유틸리티 클래스는 사용하지 않는 것이 좋다.
  • 또한 클래스가 이 자원들을 직접 만들게 하는 것 역시 안 된다. 대신 필요한 자원을 (혹은 그 자원을 만들어주는 팩터리를 ) 생성자에 (혹은 정적 팩터리나 빌더) 넘겨주자 
  • 의존 객체 주입은 클래스의 유연성, 재사용성, 테스트 용이성을 개선해준다. 

https://yeomylaoo.tistory.com/446

 

[Spring][스프링 기본편] - 10.IOC, DI, 그리고 컨테이너

1. IOC란? 제어의 역전을 의미하고 이는 제어권이 개발자에게 있는 것이 아닌 외부에 있을 때 제어의 역전이라고 한다. 이와 관련해서 프레임워크와 라이브러리를 예로 사용할 수 있다. 프레임워

yeomylaoo.tistory.com

https://yeomylaoo.tistory.com/438?category=941231 

 

[Spring][스프링 기본편] - 8. 의존관계 주입, 의존성 주입

1. 관심사의 분리 앞선 포스팅에서 살펴본 코드들은 구현체가 직접 다른 구현체를 불러오는 것과 상황이었다. -> DiscountPolicy의 구현 객체를 직접 클라이언트인 OrderServiceImpl에서 지정하여 사용하

yeomylaoo.tistory.com

Spring의 객체 주입에 대해서 정리한 포스팅 나중에 다시 기억이 안 날때 확인해서 볼 것