Skip to content

Instantly share code, notes, and snippets.

@okstring

okstring/DI.md Secret

Last active September 2, 2021 03:30
Show Gist options
  • Save okstring/8834792ce488823450ccc1d4e2b081c5 to your computer and use it in GitHub Desktop.
Save okstring/8834792ce488823450ccc1d4e2b081c5 to your computer and use it in GitHub Desktop.
의존성 주입에 대하여 설명하시오.

의존성 주입에 대하여 설명하시오.

의존성 주입이란 무엇이고 왜 사용하는 걸까요?

의존성 주입이란 클래스들로 부터의 의존성 통제의 흐름을 변경하는 방식입니다. 어떤 방식으로 할 수 있을까요? 핵심 아이디어는 주입되어질 클래스들을 한데 모아두고, 필요한 클래스에게 따로 주입해주는 방식입니다.

테스트 코드를 작성하기 위해서는 기존 코드에 의존성을 깨는 것부터 시작해야 합니다. 종속성이 감소하면 수정에 민감하지 않고, 유연성과 확장성이 높아져 테스트에 용이해지는 장점이 있습니다.

의존성 (Dependency)

의존성은 쉽게 말해 함수에 필요한 클래스나 참조 변수에 의존하는 것을 의미합니다.

class A{
    var num: Int = 1
}

class B{
    var internalVariable = A()
}

let b = B()
print(b.internalVariable.num) // 1

B클래스는 A클래스를 내부에 변수로 사용하고 있습니다. 이로써 B클래스는 A클래스에 의존성이 생깁니다.

객체끼리 의존하는 경우 많은 문제가 야기됩니다. 만일 A클래스에 문제가 생긴다면 이를 의존하고 있는 B클래스에도 문제가 생길 수 있어 재사용성이 낮아집니다. (재사용이 가능한 건 상위 클래스인 A 뿐입니다.)

이를 해결한 게 의존성 주입이죠! 일단 용어부터 천천히 알아봅시다.

주입 (Injection)

내부가 아닌 외부에서 객체를 생성해서 넣어주는 것을 주입한다고 표현합니다.

class A{
    var num: Int

    init(num : Int){
        self.num = num
    }

    func setNum(num: Int){
        self.num = num
    }
}

let a = A(Int(3)) // 외부에서 객체 생성
print(a.num)

a.setNum(Int(5)) // 객체 생성

위 예시에서는 외부에서 Int를 생성해 A클래스에 주입했습니다.

의존성 주입 (Dependency Injection)

의존성 + 주입 용어가 합쳐졌습니다. 내부에서 만든 객체를 외부에서 넣어 의존성을 주입해 봅시다.

class A{
    var aNum: Int = 1
}
class B{
    var bNum: A
    init(num: A){
        self.bNum = num
    }
}
let b = B(A())

위 코드는 클래스의 생성에서 의존성을 주입했습니다.

하지만..! 이렇게 외부에서 의존성을 주입하는 것 만으로 의존성 주입이라고 부르지 않습니다.

DI(의존성 주입)는 의존성을 분리시켜 사용합니다.

여기서 반드시 알고 넘어가야 할 개념이 있습니다.

바로 '의존 관계 역전 법칙(DIP: Dependency Injection Principal)' 입니다.

의존성 주입에서 의존성 분리는 의존 관계 역전 법칙으로 의존 관계를 분리시켜야 합니다.

의존 관계 역전 법칙 (DIP, Dependency Inversion Principle)

객체 지향 프로그래밍의 SOLID 원칙 중의 하나입니다. 의존 관계 역전 법칙은 상위 계층(정책 결정)이 하위 계층(세부 사항)에 의존하는 전통적인 의존관계를 반전시킴으로써 상위 계층이 하위 계층의 구현으로부터 독립되게 할 수 있는 구조를 말합니다. 이 법칙은 다음 두 가지 특징이 있습니다.

  1. 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.
  2. 추상화는 세부 사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.

앞선 예시는 B 클래스가 A 클래스에 의존하는 (B→A) 구조였다면, 의존 관계 역전 법칙에서는 어떤 추상화된 인터페이스(Swift 에서는 프로토콜)에 A, B 객체가 모두 의존(A → 프로토콜 ← B)하고 있는 구조라고 볼 수 있습니다.

protocol DIInterface: AnyObject{
    var num: Int{get set}
}
class A: DIInterface{
    var aNum = 1
}
class B{
    var bNum: DIInterface
    init(num: DIInterface){
        self.bNum = num
    }
}

let b = B(A())

위 구조는 A(상위 모듈), B(하위 모듈) 모두 DIInterface(추상화 프로토콜) 에 의존해있어 의존 관계를 독립 시킨 상태입니다.

이렇게 의존의 방향이 역전되어 제어가 반전되는 상황을 제어의 반전 (IoC: Inversion of Control) 이라고 표현합니다.

의존성 주입 세가지 방법

Constructor Injection(생성자 주입)

protocol Eatable {
    var calorie: Int { get }
}

struct Pizza: Eatable {
    var calorie: Int {
        return 300
    }
}

class FoodTruck {
    let food: Eatable
    
    init(food: Eatable) {
        self.food = food
    }
}

let foodTruck = FoodTruck(food: Pizza())

Property Injection

protocol Eatable {
    var calorie: Int { get }
}

struct Pizza: Eatable {
    var calorie: Int {
        return 300
    }
}

class FoodTruck {
    var food: Eatable?
}

let foodTruck = FoodTruck()
foodTruck.food = Pizza()

Method Injection

protocol Eatable {
    var calorie: Int { get }
}

struct Pizza: Eatable {
    var calorie: Int {
        return 300
    }
}

class FoodTruck {
    var food: Eatable?
    
    func setupFood(_ food: Eatable) {
        self.food = food
    }
}

let foodTruck = FoodTruck()
foodTruck.setupFood(Pizza())
view raw

의존성 주입이 가지는 이점

테스트 코드를 작성하기 위해서는 기존 코드에 의존성을 깨는 것부터 시작해야 합니다. 종속성이 감소하면 수정에 민감하지 않고, 유연성과 확장성이 높아져 테스트에 용이해지는 장점이 있습니다.

  • 테스트

  • 코드 재사용성

  • 유연성

    의존성이 발생할때 문제점을 봤었는데 유연성을 가지지 못했습니다. 만약 올바른 의존성 주입을 통한다면 해당 클래스를 고쳐도 그 클래스를 참조한곳이 없을테고 많은 부분을 수정할 필요가 없겠죠! 이렇게 이후 기능이 많아지고 꼬이는 경우를 꼭 생각하며 의존성 주입을 신경쓰면 좋습니다!

Dependency Container

https://www.youtube.com/watch?v=h2FBZcLBeq0


reference

https://eunjin3786.tistory.com/233

https://www.youtube.com/watch?v=h2FBZcLBeq0

https://sihyungyou.github.io/iOS-dependency-injection/

https://silver-g-0114.tistory.com/143

https://nadarm.tistory.com/117

https://medium.com/@jang.wangsu/di-dependency-injection-이란-1b12fdefec4f

https://donggyu9410.medium.com/ios-and-swift-의존성-주입-60faee384274

https://eunjin3786.tistory.com/115

http://minsone.github.io/ios/mac/ios-dependency-injection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment