ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DI (Dependency Injection 의존성 주입), DIP ( Dependency Inversion Principle 의존 관계 역전 원칙)
    개발 관련 2022. 3. 23. 12:00

    코드에서 Dependency 의존성이란,

    동작하는 데에 다른 클래스 등이 필요하고, 이를 사용하는 것이다.

    예를 들자면,

    SomeViewController는 SomeViewModel 타입 private let 변수를 가지고 있고

    동작에 viewModel을 사용하고 필요로 하며 의존하고 있다.

     

    의존성 주입이란

    - SomeViewModel 과 같은 필요한, 의존하고 있는 객체를

    - 외부에서 넣어주는 것이다.

     

    의존성 주입 방법

    - 프로퍼티 주입, 메서드 주입, 생성자 주입

    1. 프로퍼티 주입

     

     

    2. 메서드 주입

     

    3. 생성자 주입

    소개한 주입 방법 중에선 생성자 주입을 보통 선호한다.

    SomeViewController의 생성 시 viewModel의 주입을 강제하고, 코드 단계에서 오류를 잡아주기 때문이다.

     

    활용 목적

    - DI는 테스트 용이한 코드를 작성하기 위해서도 쓰이고

    - 변화에 유연하며 유지보수가 쉬운 코드를 만들기 위해 쓰인다.

     

    그리고 DI를 통해 이러한 코드를 만들기 위하여, DIP 원칙을 따르고 적용한다

     

     

     

    DIP, Dependency Inversion Principle 의존 관계 역전 원칙

     

    OOP, 객체 지향 프로그래밍에는 SOLID, 솔리드라고 불리는 유명한 원칙이 있다

    - S 단일 책임 (Single)

    - O 확장 열림 변경 닫힘 (Open close)

    - L 상속 관계 치환 (LSP Liskov ... 스코프  치환 원칙)

    - I 인터페이스 분리 ( Interface ... )

    - D 의존성 역전 ( DIP !! )

     

    DIP는 이 원칙 중 하나로, 클래스 간의 의존 관계를 역전한다.

     

    위에서 사용한 ViewController, ViewModel 예시에 Repository 가 추가됐다.

    - ViewController가 ViewModel의 printSth() 을 호출하고       ( ViewController는 ViewModel에 의존)

    - ViewModel은 Repository로부터 String을 받아와 출력한다.   ( ViewModel은 Repository에 의존)

     

     

     

    생성자 주입으로 의존성은 주입해주고 있으나,
    구현체 자체에 의존을 하여, 강한 결합 상태인 문제가 있다.

    이를 해결하기 위해 프로토콜 (인터페이스) 과 추상화를 사용하여 결합도를 낮춰 약한 결합 상태로 바꿔보자.

    * 결합도가 약해질 경우, 변경과 확장에 유연한 대처가 가능하다. 

    ViewModel과 Repository의 인터페이스, 프로토콜을 추가했다.

     

     

    추가한 SomeRepositoryProtocol을 준수하는, 여러 Repository 구현체들을 추가해보자.

    SomeRepository 프로토콜을 준수하는 구현체 클래스 3개가 추가됐다.

     

     

    추가 후 ViewModel의 Repository에 대한 의존을
    - 구현체 (SomeRepositoryA 등) 가 아닌, 
    - 추상타입 (SomeRepositoryProtocol) 에 의존하도록 바꿔준다.

    기존 SomeViewModel은 SomeRepository 라는 구현체에 의존하며 ViewModel - Repositry 클래스 간 결합도가 높은 강한 결합 상태였다. (Repository의 변경은 ViewModel에 필히 영향을 끼친다.)

     

    이제부터 ViewModel은 (인터페이스, 추상타입) Repository프로토콜에 의존하며, Repository의 구현에는 관심이 없고 프로토콜을 준수하는 객체를 주입하는 방식이 됐다. 덕분에 약한 결합 상태가 됐다.
    덕분에 Repository의 변경이 생기 거나, 다른 Repository가 필요할 경우, 필요한 구현체를 주입하는 방식 ex) repoA, repoB, testRepo 으로 해결이 되어 ViewModel 에선 코드 수정을 하지 않아도 된다.

     

    그러면 ViewModel과 ViewController도 마저 적용해보자.

     

    이렇게 ViewController가 ViewModel의 구현체에 의존하던 방식에서

    ViewModelProtocol, 추상 타입에 의존하며 ViewModel 구현체를 주입해주는 방식으로 바뀌었다.

     

     

    DI 기법으로 추상화, 추상 타입에 의존하도록 하고, 의존성을 외부에서 주입하도록 했다.

    모듈들은 구현체에 의존하던 방식에서 -> 추상 타입에 의존하게 됐고

    - 의존성 역전이 되고, VC - Model - Repositry 간 결합이 약한 결합이 되었다.

     

    런타임에 추상 타입의 구현체를 주입해주는 방식으로 

    향후 테스트가 용이해지고, ( Test, Mock 객체 주입 가능 )

    확장에 열리고 변화에 유연해졌다. ( 전략 패턴 등 적용 가능 )

     

    댓글

Designed by Tistory.