Tech/Spring

[스프링 핵심 원리] DIP와 생성자 주입, 의존관계 주입(DI)

0m1n 2022. 1. 1. 13:00
728x90
반응형

애플리케이션을 개발하던 중,  DIP에 위반할 수 밖에 없는 상황이 왔다.

DIP
- 의존 관계를 맺을 때 변화하기 어려운 것, 거의 변화가 없는 것에 의존

- 구현 클래스에 의존하지 말고 인터페이스에 의존해야 한다.
- 역할에 의존하게 해야 한다. (역할과 구현을 철저하게 분리하도록!!)

 

아래 코드를 보자.

private final DiscountPolicy discountPolicy = new FixDiscountpolicy();

결국 인터페이스를 참조하는게 아닌, 직접 객체를 생성을 하게 되는 것이다.

이를 해결하려면 어떻게 해야 할까?

  • 강의에서는 애플리케이션을 하나의 공연으로 비유했다.
  • 각각의 인터페이스는 배역이라고 생각할때, 해당 배역을 맡게 되는 배우를 선택하는 역할은 공연 기획자가 할 것이다.
  • 그러나 위 코드와 같은 경우는 기획자가 아닌 주인공(구현체)이 다른 주인공(구현체)을 직접 초빙하는 상황이다.
  • 따라서 공연 기획자를 만들고, 배우와 기획자의 책임을 확실히 분리할 필요가 있다.
  • 앱의 전체 동작 방식을 구성하기 위해, 구현 객체를 생성하고 연결하는 책임을 가지는 별도의 설정 클래스를 만들자.

따라서 기존에 작성했던 코드를 살펴보니 MemberServiceImpl에서 직접 MemoryMemberRepository를 호출한 것을 확인했다.

private final MemberRepository memberRepository = new MemoryMemberRepository(); // dip 위반

AppConfig에서 애플리케이션에 대한 환경설정을 모두 처리해주자.

public class MemberServiceImpl implements MemberService {
    // private final MemberRepository memberRepository = new MemoryMemberRepository(); // dip 위반
    private final MemberRepository memberRepository; // DIP 지킴

    // memberRepository 구현체가 뭐가 들어갈지를 생성자를 통해 건네줌
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

위와 같이, MemberServiceImpl에 생성자를 만들고 구현체에 뭐가 들어갈지를 생성자를 통해 건네준다.

public class AppConfig {
    public MemberService memberService(){
        return new MemberServiceImpl(new MemoryMemberRepository()); // memberService 구현체, 객체 생성
    }    
}

그 후, AppConfig에서  인스턴스를 생성해주면 DIP를 지킬 수 있게 된다!

 

따라서 `MemberServiceImpl`'MemoryMemberRepository`를 의존하지 않고 'MemberRepository` 인터페이스만 의존한다. (어떤 구현 객체를 주입할지는 오로지 `Appconfig` 에서 결정된다.

 

이와 같이 생성자를 통해서 new MemoryMemberRepository() 인스턴스가 생성된 것을 생성자 주입이라고 한다.

인스턴스(Instance) : 설계도(클래스)를 통해서 구현해야할 대상(객체)이 실제로 구현된 구체적인 실체
(인스턴스는 객체에 포함된다.)

마찬가지로, OrderService에도 적용해준다.

 

정리해보면,

  • AppConfig는 애플리케이션의 실제 동작에 필요한 구현 객체를 생성한다.
    • `MemberServiceImpl`
    • `MemoryMemberRepository`
  • AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해서 주입(연결)해준다.
    • `MemberServiceImpl`'MemoryMemberRepository`
  • 클라이언트`MemberServiceImpl` 입장에서 보면 의존관계를 마치 외부에서 주입해주는 것 같다고 해서 DI(Dependency Injection), 의존관계 주입(의존성 주입)이라고 한다.

- 이외 TIP

  • 테스트 코드에서 `@BeforeEach` 는 각 테스트를 실행하기 전에 호출한다.

 

728x90
반응형