Swift

Swift - 의존성 주입(Dependency Injection)

iosos 2023. 7. 10. 15:52

의존성 : Dependency 

- 객체 지향 프로그래밍에서 Dependency는 '서로 다른 객체 사이에 의존 관계가 있는 것'을 말함

- 즉, 의존하는 객체가 수정되면, 다른 객체도 영향을 받는다는 것 

 

import UIKit

// 의존성이 있는 프로토콜
protocol Talk {
    func sayHi()
}


// Talk 프로토콜을 채택하여 구현한 클래스
class FriendTalk : Talk{
    func sayHi() {
        print("FriendTalk - sayHi()")
    }
}

// 의존성을 주입받은 클래스
class LetsTalk{
    private let talk : Talk
    
    init(){
        self.talk = FriendTalk()    //FriendTalk 인스턴스를 직접 생성하여 주입 
    }
    
    func sayHi(){
        talk.sayHi()
    }
}

- LetsTalk 클래스의 생성자에서 FriendTalk 인스턴스를 직접 생성하여 talk 프로퍼티에 할당 -> 의존성 문제 발생

- 이 부분에서 생성자 주입을 사용하지 않고 의존성을 직접 생성하고 주입하기 때문에 의존성 문제가 발생함 

- FriendTalk 객체에 중요한 수정이나 오류가 발생한다면 LetsTalk 객체도 영향을 받을 수 있다

- 의존성을 가지는 코드가 많아진다면, 재활용성이 떨어지고 매번 의존성을 가지는 객체들을 함께 수정해주어야 함 -> 의존성 주입으로 해결 

 

 

 

 

 

Dependency Injection (의존성 주입)

 

* 사용 이유

- Unit Test가 용이해짐

- 코드의 재활용성 높여줌

- 객체 간의 의존성을 줄이거나 없앨 수 있음

- 객체 간의 결합도를 낮추면서 유연한 코드를 작성 가능 

 

 

* Injection (주입)

- 외부에서 객체를 생성해서 넣는 것 

 

 

 

* 사용 방법

 

1. 프로토콜 정의

// 의존성이 있는 프로토콜
protocol Talk {
    
    var saying : String {get set}
    func sayHi()
}

- 프로토콜은 Swift에서 인터페이스에 해당하는 역할을 수행하는 기능

- 프로토콜을 채택하는 클래스는 프로토콜의 속성과 메서드 구현을 강제화 함 

 

 

 

 

 

2. 프로토콜을 채택하여 구현한 클래스 작성

// Talk 프로토콜을 채택하여 구현(준수)한 클래스
class FriendTalk : Talk{
    
    var saying : String = "FriendTalk 입니다."
    
    func sayHi() {
        print("FriendTalk - sayHi()")
    }
}


// Talk 프로토콜을 채택하여 구현(준수)한 클래스
class ParentsTalk : Talk{
    
    var saying : String = "ParentsTalk 입니다."
    
    func sayHi() {
        print("ParentsTalk - sayHi()")
    }
}

- Talk 프로토콜을 채택한 FriendTalk, ParentsTalk 클래스를 구현 

- 두 클래스는 각자 saying 속성과 sayHi() 메서드를 구현해야 함 

 

 

 

 

 

3. 프로토콜에 대한 의존성을 주입 받는 클래스 작성

// 의존성을 주입 받은 클래스
class LetsTalk{
    var talkProvider : Talk
    
    var saying : String{
        talkProvider.saying
    }
    
    init(talk : Talk){
        self.talkProvider = talk
    }
    
    func sayHi(){
        talkProvider.sayHi()
    }
}

- Talk 프로토콜을 준수하는 어떤 객체도 받을 수 있는 talkProvider 프로퍼티 선언

- talkProvider의 saying 값을 반환하는 saying 프로퍼티 선언

- init(talk : Talk) 생성자를 통해 외부에서 Talk 프로토콜을 준수하는 객체를 주입 받아 talkProvider에 할당 

- 프로토콜을 준수하는 객체를 클래스 내부에서 생성하여 할당하는 것이 아닌 외부에서 받아와 할당하므로 의존성 문제를 해결함 

 

 

 

 

 

 

4. 프로토콜을 준수한 객체를 외부에서 생성하여 할당

let letsTalk = LetsTalk(talk: FriendTalk())
letsTalk.sayHi()
print(letsTalk.saying)

print("===================")

let letsTalk2 = LetsTalk(talk: ParentsTalk())
letsTalk2.sayHi()
print(letsTalk2.saying)

- letsTalk 인스턴스를 생성할 때 FriendTalk() 인스턴스를 주입하여 LetsTalk 클래스의 객체 생성 

- letsTalk 인스턴스의 talkProvider 프로퍼티엔 FriendTalk 객체가 할당 

- 즉, letsTalk 객체는 FriendTalk 클래스를 의존성으로 주입 받아 그 기능을 활용하고 의존성 객체의 속성 값이나 메서드에 접근 가능 

 


전체 코드

import UIKit

// 의존성이 있는 프로토콜
protocol Talk {
    
    var saying : String {get set}
    func sayHi()
}


// Talk 프로토콜을 채택하여 구현(준수)한 클래스
class FriendTalk : Talk{
    
    var saying : String = "FriendTalk 입니다."
    
    func sayHi() {
        print("FriendTalk - sayHi()")
    }
}


// Talk 프로토콜을 채택하여 구현(준수)한 클래스
class ParentsTalk : Talk{
    
    var saying : String = "ParentsTalk 입니다."
    
    func sayHi() {
        print("ParentsTalk - sayHi()")
    }
}


// 의존성을 주입 받은 클래스
class LetsTalk{
    var talkProvider : Talk
    
    var saying : String{
        talkProvider.saying
    }
    
    init(talk : Talk){
        self.talkProvider = talk
    }
    
    func sayHi(){
        talkProvider.sayHi()
    }
}


let letsTalk = LetsTalk(talk: FriendTalk())
letsTalk.sayHi()
print(letsTalk.saying)

print("===================")

let letsTalk2 = LetsTalk(talk: ParentsTalk())
letsTalk2.sayHi()
print(letsTalk2.saying)

 

 

참고) 

https://80000coding.oopy.io/68ee8d89-5d05-449d-87e2-5fba84d604ca 

 

(Swift) Dependency Injection, 의존성 주입이란? (feat. DIP)

Dependency Injection, 의존성 주입..

80000coding.oopy.io

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