본문 바로가기
public void static main()/Book

[Effective Java] 아이템 5

by 햄리뮤 2023. 1. 24.
반응형

 

[책 규칙]

노란색 - 자세히 알아보고싶은 부분

초록색 - 핵심 개념 (블로그 정리시는 검은색으로!)

빨간색 - 무슨말인지 모르겠는 부분

[아이템 5] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

유틸리티 클래스?
프로젝트 진행시 여러 클래스에서 공통적으로 사용되는 메서드가 발생할 수 있다. 이때, 관련된 메서드들끼리 모아서 클래스로 만든다면 중복된 코드가 발생하지 않고 효율적으로 관리할 수 있다. 이를 Utility Class 또는 Helper Class 라고 한다!
public class SpellChecker {
  // 정적 유틸리티를 잘못 하용한 예 - 유연하지 않고 테스트하기 어렵다.
  private static final Lexicon dictionary = "";
  
  private SpellChecker() { // 객체 생성 방지
    
  }
  public static boolean isValid (String world) {
    return false;
  }

  public static List<String> suggestions(String typo) {
    return null;
  }
}
public class ShellCheckerBadCase02 {
  // 싱글턴을 잘못 사용한 예 - 유연하지 않고 테스트하기 어렵다.
  private static final Lexicon dictionary = "";

  private ShellCheckerBadCase02() {

  }
  
  public static ShellCheckerBadCase02 INSTANCE = new ShellCheckerBadCase02();
  
  public boolean isValid (String world) {
    return false;
  }

  public List<String> suggestions(String typo) {
    return null;
  }
}

두 방식 모두 사전을 단 하나만 사용한다고 가정한다는 점에서 그리 훌륭해 보이지 않는다!

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

 

대신 클래스(SpellChcker)가 여러 자원 인스턴스를 지원해야 하며, 클라이언트가 원하는 자원(dictionary)을 사용해야 한다. 이조건을 만족하는 간단한 패턴이 있으니, 바로 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이다.

 

의존 객체 주임의 한 형태로, 의존 객체를 주입해주면된다.

public class SpellCheckerGoodCase {
  // 이존 객체 주입은 유연성과 테스트 용이성을 높여준다.
    private final Lexicon dictionary;

  private SpellCheckerGoodCase(Lexicon dictionary) {
    this.dictionary = Objects.requireNonNull(dictionary);
  }

  public boolean isValid (String world) {
    return false;
  }

  public List<String> suggestions(String typo) {
    return null;
  }
}

위 코드에서는 딱 하나의 자원만 사용하지만, 자원이 몇 개든 의존 관계가 어떻든 상관없이 잘 작동한다. 또 한 불변을 보장하여 여러 클라이언트가 의존 객체들을 안심하고 공유할 수 있기도 하다. 의존 객체 주입은 생성자, 정적 팩터리, 빌더 모두에 똑같이 응용할 수 있다.

또한, 생성자에 자원 팩터리를 넘겨주는 방식이 있다.

팩터리란?
호출할 때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체를 말한다. 즉, 팩터리 메서드 패턴을 구현한 것이다.

의존 객체 주입이 유연성과 테스트 용이성을 개선해주긴 하지만, 의존성이 수천 개나 되는 큰 프로젝트에서는 코드를 어지럽게 만들기도 한다. 

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

 

1. 아이템 개념

  • 의존성 주입(Dependency Injection)은 클래스간 의존성을 클래스 외부에서 주입하는 것을 뜻한다. 더 자세하게는 의존성 주입은 클래스에 대한 의존성의 인터페이스화를 통한 코드 유연성 증대와 클래스의 인스턴스를 외부에서 생성하여 주입하는 것을 뜻한다.
  • 외부에서 두 객체 간의 고나계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.

2. 필요한 이유

  • 두 클래스가 강하게 결합되어있을때
  • 객체들 간의 관계가 아니라 클래스 간의 관계가 맺어졌을때

3. 아이템 개념의 반대 개념이나 관련 개념

  • 생성자 주입(추천)
    • 생성자의 호풀시점에 1회 호출되는 것이 보장된다.
    • 주입 받은 객체가 변하지 않는다.
    • DI를 강제할 수 있다.
public class MemberService {
   private MemberRepository memberRepository;
   
   @Autowired
   public MemberService(MemberRepository memberRepository){
      this.memberRepository = memberRepository
   }
}
  • 수정자 주입
    • 장점: 객체 생성 이후에도 객체를 변경시킬 수 있다.
    • 선택적으로 생성해야하는 객체나 변경이 발생하는 의존 관계에서 사용할 수 있다.
@Service
public class UserService {

    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
}
  • Field 주입
    • 장점: 코드가 간결해진다.
    • 단점: 외부에서 변경이 불가능해진다. 테스트 코드 작성시 객체 수정이 불가능하므로 어려움을 겪게 됨.
public class TestConectoller {

	@Autowired
    private TestService testService;
}

4. 실무에서는 어떤식으로 사용되는가 (실제 코드 사용예시) 위 개념에서 알아봤다!

5. 장점

  • 의존성이 줄어든다
    • 의존한다는 것은 그 의존대상의 변화에 취약하다는 것이다. DI로 구현하게 되었을 때, 주입받는 대상이 변하더라도 그 구현 자체를 수정할 일이 없거나 줄어들게 된다.
  • 재사용성이 높은 코드가 된다.
  • 테스트하기 좋은 코드가 된다.
  • 기능들을 별도로 분리하게 되어 가독성이 높아진다.

6. 단점

  • 간단한 프로그램을 만들 때 번거롭다.
  • 의존성 주입은 동작, 구성을 분리하기 때문에 코드 추적이 어렵고, 가독성을 떨어뜨릴 수 있다.

 

 

 

 

 

 

 

 

 

 

 

https://mangkyu.tistory.com/125

 

[Spring] 다양한 의존성 주입 방법과 생성자 주입을 사용해야 하는 이유 - (2/2)

Spring 프레임워크의 핵심 기술 중 하나가 바로 DI(Dependency Injection, 의존성 주입)이다. Spring 프레임워크와 같은 DI 프레임워크를 이용하면 다양한 의존성 주입을 이용하는 방법이 있는데, 각각의 방

mangkyu.tistory.com

https://goni95.tistory.com/15

 

Dependency Injection : 의존성 주입

1. DI(의존성 주입) DI를 그대로 번역한 의존성 주입이란 용어를 사용해 "무슨 뜻이야?"라는 생각이 듭니다. 찬찬히 알아보겠습니다. 우선 의존성 주입(DI)의 개념은 "하나의 객체에 다른 객체의 의

goni95.tistory.com

https://mangkyu.tistory.com/150

 

[Spring] 의존성 주입(Dependency Injection, DI)이란? 및 Spring이 의존성 주입을 지원하는 이유

1. 의존성 주입(Dependency Injection)의 개념과 필요성 [ 의존성 주입(Dependency Injection) 이란? ] Spring 프레임워크는 3가지 핵심 프로그래밍 모델을 지원하고 있는데, 그 중 하나가 의존성 주입(Dependency Inj

mangkyu.tistory.com

https://tecoble.techcourse.co.kr/post/2021-04-27-dependency-injection/

 

의존관계 주입(Dependency Injection) 쉽게 이해하기

이번 글에서는 DI(의존성 주입, 의존관계 주입)의 개념을 설명한다.

tecoble.techcourse.co.kr

https://spongeb0b.tistory.com/100

 

[Java] 유틸리티 클래스란 무엇인가?

유틸리티 클래스란 무엇인가? 어려운 개념은 없고 그냥 용어이다. 유틸리티 클래스는 인스턴스 메서드와 인스턴스 변수를 일절 제공하지 않고 정적 메서드와 변수만을 제공하는 클래스를 뜻한

spongeb0b.tistory.com

** 그냥 하루하루 개인 공부한 것을 끄적 거리는 공간입니다.

이곳 저곳에서 구글링한 것과 강의 들은 내용이 정리가 되었습니다.

그림들은 그림밑에 출처표시를 해놓았습니다.

문제가 될시 말씀해주시면 해당 부분은 삭제 하도록하겠습니다. **

 

 

 

반응형

'public void static main() > Book' 카테고리의 다른 글

[Effective Java] 아이템 23  (0) 2023.01.24
[Effective Java] 아이템 18  (0) 2023.01.24
[Effective Java] 아이템 17  (0) 2023.01.18
[Effective Java] 아이템 15  (0) 2023.01.18
[Effective Java] 아이템 13  (0) 2023.01.10

댓글