프로그래밍/JAVA

[JAVA] Effective Java - 5. 자원을 직접 명시하지 말고 의존 객체 주입 사용

하나만알자 2022. 9. 14. 00:03
반응형

보통 클래스는 하나 이상의 자원에 의존한다.

 

예시가 생각나지 않아 책에 나온 예시를 참조 하였다.

맞춤법 검사기는 사전에 의존하게 되는데, 이런 클래스들을

유틸리티 클래스 또는 싱글턴으로 구현한 모습을 드물지않게 볼 수 있다.

// 정적 유틸리티
class SpellChecker {
  private final Lexicon dictionary = new KoreanLexicon();

  private SpellChecker() {}

  public static boolean isValid(String word) {
    //..
  }
}
// 싱글턴 
class SpellChecker {
  private final Lexicon dictionary = new KoreanLexicon();

  private SpellChecker() {}
  public static SpellChecker INSTANCE = new SpellChecker();

  public boolean isValid(String word) {
    //..
  }
}

 

두 케이스 모두 잘못사용한 예로 들 수 있다. -> 사전을 국어사전만 사용할 수 있음.

이때, 여러 사전을 사용할 수 있도록 사전을 교체하는 메서드(setter)를 추가하게 되면 오류를 유발할 수 있고,

멀티스레드 환경에서는 사용할 수 없다.(불변 보장X)

 

사용하는 자원에 따라 동작이 달라지는 클래스의 경우에는 정적 유틸리티 클래스, 싱글턴 클래스 방식이 적절하지않다.

대안으로 의존 객체 주입이 있다.

인스턴스를 생성할 때, 생성자에 필요한 자원을 넘겨주는 방식

 

// 의존성 주입
class SpellChecker {
  private final Lexicon dictionary;

  public SpellChecker(Lexicon dictionary) {
    this.dictionary = Objects.requireNonNull(dictionary);
  }

  public static boolean isValid(String word) {
    //..
  }
}

자원이 몇개든 의존관계가 어떻든 상관없이 잘 작동하고

불변을 보장하여 여러 클라이언트가 안심하고 사용 가능하다.

생성자, 정적 팩터리, 빌더 모두 적용가능.

 

 

생성자에 자원 팩터리를 넘겨주는 방식도 가능

class Mosaic {
  public static Mosaic create(Supplier<? extends Tile> tileFactory) {
    Tile tile = tileFactory.get();
    // ..
  }
}
// 상위 타입
interface Tile {
  void setColor(String color);
}

// 하위 타입
class CheckTile implements Tile {
  public void setColor(String color) {}
}
// 검은색 컬러 속성을 가지게 하는 객체 자원 팩터리를 넘겨준다.
Mosaic m = Mosaic.create(() -> {
  CheckTile checkTile = new CheckTile();
  checkTile.setColor("black");
  return checkTile;
});

명시된 타입의 하위 타입이라면 무엇이든 생성할 수 있는 팩터리를 넘길 수 있다.

 

의존성이 많아지면 코드를 어지럽게 만들기도 한다.

스프링같은 프레임워크를 사용하면 간단하게 해소할 수 있다.

반응형