Study/Effective-Java

[item#05] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

hongeeii 2023. 11. 27.
728x90
반응형

IOC(Inversion of Controll), DI(dependency injection)

  • 사용하는 자원에 따라 동작이 달라지는 클래스는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.
  • 의존 객체 주입이란 인스턴스를 생성할 때 필요한 자원을 넘겨주는 방식이다.
  • 의존 객체 주입을 사용하면 클래스의 유연성, 재사용성, 테스트 용이성을 개선할 수 있다.

==================================================================================================

public class SpellChecker {
    private static final Dictionary dictionary = new Dictionary();

    private SpellChecker() {
    }

    public static boolean isVaild(String word) {
        // TODO 여기 SpellChecker 코드
        return dictionary.contains(word);
    }

    public static List<String> suggestions(String typo) {
          // TODO 여기 SpellChecker 코드
        return dictionary.closeWordsTo(typo);
    }
} 

위와 같은 Utils성 Class의 문제.

  1. Dictionary를 변경 불가(한국어 사전인지, 영어사전인지 등...)
  2. Dictionary를 생성하는데 많은 비용이 든다고 가정하에, SpellChecker만의 코드를 test할 때 필요없는 자원 필요
    @Test
     void isVaild() {
         assertTrue(SpellChecker.isVaild("test"));
     }
    
  3. 유연하지 않고 test코드 작성 시 불편
  4. Utils성이 아니라 Singleton으로 작성시에도 마찬가지. (유연성 재사용성 떨어짐)

DI를 사용한 코드

public class SpellChecker {
    private final Dictionary dictionary; // Dictionary가 인터페이스일 때 유연, 재사용성

    public SpellChecker(Dictionary dictionary) {
        this.dictionary = dictionary;
    }

    public boolean isVaild(String word) {
        // TODO 여기 SpellChecker 코드
        return dictionary.contains(word);
    }

    public List<String> suggestions(String typo) {
        return dictionary.closeWordsTo(typo);
    }
}

public interface Dictionary {
    boolean contains(String words);

    public List<String> closeWordsTo(String typo);
}

장점 1. Dictionary를 언제든지 갈아 끼울 수 있는 유연함.
장점 2. Mock Dictionary를 만들어 test의 용의함.

@Test
    void isVaild() {
        SpellChecker spellChecker = new SpellChecker(new DefaultDictionary());
        assertTrue(spellChecker.isVaild("test"));
    }

DI 패턴의 변형

  • DI 변형으로 생성자에 자원 팩터리를 넘겨줄 수 있다.
  • Supplier 인터페이스가 팩터리를 표현한 완벽한 예
  • 한정적 와일드카드 타입을 사용해 팩터리의 타입 매개변수를 제한해야 한다. => Dictionary를 인터페이스로 구현하면 됨
  • 의존 객체가 많은 경우에 스프링 같은 의존 객체 주입 프레임워크 도입을 고려할 수 있다.
     public SpellChecker(DictionaryFactory dictionaryFactory) {
       this.dictionary = dictionaryFactory.get();
   }

자원을 바로 받는게 아니라 자원을 만들어주는 팩터리를 받아서 중간단계를 조금 더 추상화 한 방식
Dictionary가 만들어지는 방식이 복잡한 경우에 사용할 수 있다.

public SpellChecker(Supplier<Dictionary> dictionarySupplier) {
        this.dictionary = dictionarySupplier.get();
    }
  
SpellChecker spellChecker = new SpellChecker(DefaultDictionary::new);
SpellChecker spellChecker = new SpellChecker(DictionaryFactory::get2);  
  

BeanFactory또는 ApplicationContext

  • Inversion of Control - 뒤짚힌 제어권
    • 자기 코드에 대한 제어권을 자기 자신이 가지고 있지 않고 외부에서 제어하는 경우
    • 제어권? 인스턴스를 만들거나, 어떤 메소드를 실행하거나, 필요로하는 의존성을 주입 받는등...
  • 스프링 IOC 컨테이너 사용 장점
    • 수많은 개발자에게 검증되었으며 자바 표준 스팩(@Inject)도 지원
    • 손쉽게 싱글톤 Scope을 사용 가능
    • 객체 생성(Bean) 관련 라이플 사이클 인터페이스 제공

스프링 - 비 침투적인(프레임워크가 제공하는 코드가 노출되는 코드 - 침투적인 코드), POJO를 유지.

IOC코드 등은 패스...

팩토리 메서드 패턴

image
image

https://dev-youngjun.tistory.com/195

Product Interface

public interface Dictionary {
    boolean contains(String words);
    

    public List<String> closeWordsTo(String typo);
}

Creator Interface

public interface DictionaryFactory {
    Dictionary getDictionary();
}

ConcreteCreator

public class DefaultDictionaryFactory implements DictionaryFactory {

    @Override
    public Dictionary getDictionary() {
        return new DefaultDictionary();
    }

}

사용

public class SpellChcker {
    private Dictionary dictionary; // product interface

//	public SpellChcker(DictionaryFactory dictionaryFactory) {
//		this.dictionary = dictionaryFactory.getDictionary();
//	}
    public SpellChcker(Supplier<DictionaryFactory> dictionarySupplier) {
        this.dictionary = dictionarySupplier.get().getDictionary();
    }

    public static void main(String[] args) {
        SpellChcker chcker = new SpellChcker(DefaultDictionaryFactory::new);
        SpellChcker chcker2 = new SpellChcker(MockDictionaryFactory::new);

    }
}
728x90
반응형

추천 글