본문 바로가기

프로그래밍/JAVA

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

반응형

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

 

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

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

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

// 정적 유틸리티
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;
});

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

 

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

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

반응형