본문 바로가기
Design Patterns/DI(Dependency Injection)

Dependency Injection(DI: 의존성 주입)

by 탄이. 2020. 1. 26.

[DI] Dependency Injection 이란? - Clint Jang - Medium

Dependency Injection

  1. 높은 재사용성
  2. 테스트 용이
  3. 코드 단순화
  4. 종속적인 코드 줄여줌
  5. 코드 의도 파악 수월.
  6. 종속성 감소
    • 구성 요소의 종속성이 감소하면 변경에 민감하지 않습니다
  7. 결합도(coupling)는 낮추면서 유연성과 확장성은 향상
  8. 객체 간의 의존관계 설정
  9. 객체 간의 의존관계를 없애거나 줄임

의존성

class AClass {
    var number: Int = 1
}

// AClass와 의존관계가 있는 클래스
class BClass {
    // 내부에 변수로 AClass를 사용
    var internalVariable = AClass()
}

let b = BClass()
print(b.internalVariable.number)
  • B 클래스에서 A 클래스를 내부에 변수로 사용하게 됨으로써 B 클래스는 A 클래스에 의존관계가 생기게 됩니다.

주입

  • 내부가 아니라 외부에서 객체를 생성해서 넣어주는 것

    class BClass {

      var number: Int
    
      init(WithNumber number: Int) {
          self.number = number
      }
    
      func setNumber(number: Int) {
          self.number = number
      }

    }

    // 외부에서 객체를 생성해서 넣습니다.
    let b = BClass(WithNumber: Int(3))
    print(b.number)

    // 외부에서 객체를 생성해서 넣습니다.
    b.setNumber(number: Int(5))
    print(b.number)

  • 내부에서 만든 변수를 외부에서 넣어주게 한다.

    class AClass {

      var number: Int = 1

    }

    // AClass와 의존관계가 있는 클래스
    class BClass {

      // 내부에 변수로 AClass를 사용할 것임
      var internalVariable = AClass
    
      init(WithExternalVariable variable: AClass) {
          // 외부에서 AClass 객체를 받습니다.
          self.internalVariable = variable
      }

    }

    // 외부에서 AClass를 BClass에 주입합니다.
    // 제어의 주체가 외부에 있습니다.
    let b = BClass(WithExternalVariable: AClass())
    print(b.internalVariable.number)

의존성 분리

  • 의존관계 역전 원칙

Protocol 사용

  • 상위계층이 하위계층에 의존하게 되는 상황을 반전시켜서 하위 계층의 구현으로부터 독립

    // 의존 관계를 독립시킬 인터페이스
    protocol DependencyIndependentInterface: AnyObject {

      var number: Int { get set }

    }

    // 위의 인터페이스에 의존관계가 있는 클래스
    class AClass: DependencyIndependentInterface {

      var number = 1

    }

    // AClass와 의존관계가 있는 클래스
    class BClass {

      // 내부에 변수로 AClass를 사용할 것임
      var internalVariable: DependencyIndependentInterface
    
      init(WithExternalVariable variable: DependencyIndependentInterface) {
          // 외부에서 AClass 객체를 받습니다.
          self.internalVariable = variable
      }

    }

    // 외부에서 AClass를 BClass에 주입
    // 제어의 주체가 외부에 있음
    let b = BClass(WithExternalVariable: AClass())
    print(b.internalVariable.number)

  • 제어의 주체가 Protocol에게 있으므로 Protocol만 파악하면 분석이 수월하다.

  • 의존관계 역전 == 의존의 방향이 역전 되었다(구조적 설계와 비교하여) == 의존의 전이를 끊었다. == IOC

제어의 반전 (IOC: Inversion of Control)

  • 전통적 프로그래밍
    • 프로그래머가 작성한 프로그램이 외부 라이브러리의 코드를 호출해 이용하는 흐름
  • 제어 반전이 적용된 구조
    • 외부 라이브러리의 코드가 프로그래머가 작성한 코드를 호출

목적

  • 작업을 구현하는 방식과 작업 수행 자체를 분리합니다.
  • 모듈을 제작할 때, 모듈과 외부 프로그램의 결합에 대해 고민할 필요 없이 모듈의 목적에 집중할 수 있습니다.
  • 다른 시스템이 어떻게 동작할지에 대해 고민할 필요 없이, 미리 정해진 협약대로만 동작하게 하면 됩니다.
  • 모듈을 바꾸어도 다른 시스템에 부작용을 일으키지 않습니다.

IOC Container

  • IOC를 구현하는 프레임워크로 객체를 관리하고, 객체의 생성을 책임지고, 의존성을 관리하는 컨테이너
  • IOC Contatner는 큰그림/설계도를 작성해놓은 인터페이스 같은 것
  • 객체가 직접 인스턴스를 연결해주면 인터페이스(Protocol)가 알아서 등록된 함수들을 주입해주는 개념
  • 인터페이스(Protocol)의 연관성이 있는 인스턴스를 연결시킨 객체를 사용함으로써 자동으로 연관성이 생겨서 Dependency를 주입한다는 의미가 되는 DI의 핵심 개념

댓글