Jun 개발노트

DI, DIP

2022-04-17

0. 글을 작성하는 이유

  • 클린아키텍처 책을 읽다가.. DIP가 궁금해서
  • DI, DIP 대해 정의만이라도 정확히 알고 싶어서

TL;DR

didip.png

  • Case1
    • User 객체는 MySQLDAL 의존하고 있다.
    • 문제 : MySQLDAL이 바뀌면, 의존하고 있는 User도 수정해야 된다
  • Case2
    • Case1 해결 : 해당 의존 관계를 외부로 부터 주입받아 Case1 문제를 해결할 수 있다.
    • 문제: DB가 바뀌었다면(MySQL → Oracle 변경) User가 수정되어야 한다.
  • Case3
    • 해결: Interface 주입함으로써, DB가 어떤 종류 인지 알 필요가 없다(결합도 ↓)

1. 의존성이란?

  • 두 모듈(컴포넌트) 관계(객체지향에서는 두 클래스 간의 관계)
  • 둘 중 하나가 다른 하나를 어떤 용도를 위해 사용함

1) 기본적인 소스코드 의존성 및 제어흐름

  • 전형적인 호출 트리의 경우 main 함수가 고수준 함수 호출
    • 고수준 함수 → 중간함수 → 저수준 함수 호출
  • 소스 코드 의존성의 방향은 반드시 제어 흐름을 따르게 된다.

flow.png

Source code dependencies vs flow of control — Martin, Robert C. 2017. Clean Architecture —  A Craftsman’s Guide to Software Structure and Design. Prentice Hall. Ch. 5. Figure 5.1.

2. 의존성 문제

  • UserMySQLDAL 의존하고 있는 상태

  • MySQLDAL 변경된다면, 의존하고 있는 User도 수정해야 되는 문제!!

    class MySqlDal{};
    
    class User{
        protected $dal;
    
        constructor(){
            this.$dal = new MySqlDal();
        }
    }
    

    1) DI - 의존성 주입

    • 외부로 부터 의존성을 주입받아 의존성 문제를 해결 할 수 있다.

    • 단, 해당 User는 Mysql에 의존되고 있는 상황... 만약 DB가 Oracle로 변경된다면?

      class MySqlDal{};
      
      class User{
          protected $dal;
      
          constructor(MySqlDal : MySqlDal){
              this.$dal = MySqlDal;
          }
      }
      

    2) DIP - 의존성 역전

    • 인터페이스 주입을 통해 User는 Oracle, MySql인지 알 필요가 없어졌다.(결합도 ↓)

    • 인터페이스를 기준으로 기능 구현을 강제하기 때문, 어떤 DB든지 상관없다.

      flow.png

      interface DBConnnect{
          connect: () => void
      }
        
      class MySql implements DBConnnect {
          connect(){
              console.log('connet')
          }
      }
      class Oracle implements DBConnnect {
          connect(){
              console.log('connet')
          }
      }
        
      class User {
          protected $dal;
        
          constructor(dal : DBConnnect){
              this.$dal = dal;
          }
        
      }
      

참고