DI를 사용하는 이유

yanju·2022년 12월 3일
0
post-thumbnail

의존성 주입은 프로그램 디자인이 결합도를 느슨하게 한다.

의존성 주입은 의존관계 역전 원칙과 단일 책임 원칙을 따르도록 한다.

클라이언트의 객체 생성에 대한 의존성을 클라이언트의 행위로부터 분리하는 것이다.

의존성 주입은 다음과 같은 문제를 해결한다.

  • 어떻게 애플리케이션이나 클래스가 객체의 생성 방식과 독립적일 수 있는가?
  • 어떻게 객체의 생성 방식을 분리된 구성 파일에서 지정할 수 있는가?
  • 어떻게 애플리케이션이 다른 구성을 지원할 수 있는가?

객체를 필요로하는 클래스 내에서 직접 객체를 생성하는 것은 클래스를 특정 객체에 커밋하는 것이다.

이후에 클래스로부터 독립적으로(클래스의 수정 없이) 인스턴스의 생성을 변경하는 것이 불가능하기 때문에 유연하지 못하다.

이는 다른 객체를 필요로하는 경우 클래스를 재사용할 수 없게한다.

또한 실제 객체를 모의 객체로 대체할 수 없기 때문에 클래스를 테스트하기 힘들게한다.

DI 등장 예시

  1. MemberServiceImpl에서 Member를 저장하는 Repository를 JDBC로 사용중이다.
  2. 갑자기 JDBC -> JPA로 요구사항이 변경됐다.
  3. 이런 상황을 대비해서 인터페이스를 잘 설계한 자신에게 흡족해하며 새로운 JpaMemberRepository 구현클래스를 만들고 적용했다.
// 변경 전
public class MemberServiceImpl implements MemberService {

    MemberRepository memberRepository = new JdbcMemberRepository();

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

}

// 변경 후
public class MemberServiceImpl implements MemberService {

    MemberRepository memberRepository = new JpaMemberRepository(); // 여기가 변경됨

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

}

위 코드는 객체지향 설계 원칙에 어긋나는 코드다.

객체지향 설계 원칙 중 SRP, OCP, DIP에 위반한 상황이다.

  • SRP 단일 책임 원칙 (Single Responsibility Principle)
    • 한 클래스는 하나의 책임만 가져야 한다.
  • OCP 개방-폐쇄원칙 (Open/Closed Principle)
    • 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀있어야 한다.
  • DIP 의존관계 역전 원칙 (Dependency Inversion Principle)
    • 구체화에 의존하지 말고 추상화에 의존해야 한다.
    • 클라이언트 코드가 구현클래스에 의존하지 말고, 인터페이스에 의존해야한다.
MemberRepository memberRepository = new JdbcMemberRepository();
MemberRepository memberRepository = new JpaMemberRepository();
  • SRP 위반
    • 클라이언트 코드가 본인의 로직 실행 이외에 의존관계 책임까지 신경쓰고있다.
  • DIP 위반
    • 추상(인터페이스)와 함께 구체(구현)클래스에도 의존하고 있다.
      • 추상 의존: MemberRepository
      • 구체 의존: JdbcMemberRepository, JpaMemberRepository
  • OCP 위반
    • 새로운 요구사항에 맞춰 기능이 확장됐고, 동시에 클라이언트 코드에 변경이 일어났다.
      • new JdbcMemberRepository() -> new JpaMemberRepository()

다음과 같이 바꾸어 의존성 주입을 활용한다.

인터페이스만 의존하도록 설계를 변경해야한다.

public class MemberServiceImpl implements MemberService {

    MemberRepository memberRepository;
    
    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }
}

참고

https://ko.wikipedia.org/wiki/의존성_주입

https://velog.io/@roro/DI-Dependency-Injection-사용이유

0개의 댓글