1. 의존성 주입Dependency Injection) 이란?
Giving an object its instance variables, instead of creating them in the object.
이 말은 즉슨, 인스턴스 변수를 객체 안에서 생성하는 것이 아니라 외부에서 객체에게 주는 것
2. 왜 의존성 주입이 필요한가?
결론은 유지보수를 쉽게 하려고 하는 게 목적이다. 즉 노가다를 하지 않기 위해서이다.
조금 더 풀어쓰면 대표적으로 4가지의 이유가 있다.
- Transparency(투명성)
- 객체에게 요구되는 책임과 필요조건이 보다 명확하고 투명성있게 볼 수 있다.예를 들어 ViewController에 DataManager를 주입시킴으로써 ViewController가 DataManger에게 의존을 하고 있고,데이터 매니징에 책임을 가지고 핸들링 하는 것을 의존성 주입을 통해 예상할 수 있다.
- Testing(테스팅)
- 의존성 주입 시 Mock 객체로 교체할 수 있기 때문에 테스트에 용이하다.
- Separation of Concerns(이해관계의 분리)
- DataManger가 Serializer의 행위와 이해관계가 있더라도 DataManager는 Serializer 인스턴스를 만드는 방법을 알 필요가 없다. 주입만 받으면 된다.
- Reducing Coupling(결합도 줄이기)
- DataManager는 프로토콜 사용하는 행위만 고려할 뿐, 구체적인 인스턴스의 행위를 알 필요가 없다. 즉 주입할 객체와의 결합도를 줄여주는데, 이는 유연성이 있는 코드 작성을 도와 코드의 재활용성을 높여준다.
3. 어떻게 의존성 주입을 하는가?
우선 의존한다는 것은 무엇일까? A가 B를 의존한다는 말은 B가 변하면 그것이 A에 영향을 미친다는 의미이다.
개발분야에서는 새로운 기능이 추가되기도 삭제되기도 한다. 이런 상황에서 의존성이 커지면 유지 보수가 매우 어렵다.
그래서 의존성 역전의 원칙이라는 말이 나온다. 구체적인 객체는 추상화된 객체에 의존을 해야 한다. 그렇게 해야 유지보수 관점에서 유리하다. 구체적인 객체는 추상화된 객체보다 변화가능성이 높다. 추상화된 객체가 이런 구체적인 객체에 의존하게 되면, 노가다를 해야한다..
즉 구체적인 객체는 추상화된 객체에 의존을 해야 한다는 원칙이 의존성 역전의 원칙이다. 그럼 역전이라는 말은 왜 나왔는지 궁금할 수 있다.
이는 의존성이 제어의 흐름과 반대이기 때문이다. 추상적인 객체는 구체적인 객체가 제어를 한다.
구체적으로 의존성을 주입할 객체의 변수를 프로토콜(추상화) 속성으로 선언해두면, 즉 의존 관계를 인터페이스로 추상화하면, 더 다양한 의존 관계를 맺을 수 있고, 실제 구체적인 객체와의 결합도가 낮아진다.
4. 의존성 주입의 종류
- Initializer Injection 장점은 초기화 과정에서 immutable하게 만들 수 있다.즉 초기화 과정에서 한 번 의존성 주입을 하면 이후에 변경이 불가능하다.
- Property Injection internal 혹은 public으로 접근 제어자를 선언함으로써 외부에서 의존성 주입을 한다.mutable한데 사용하는 이유는 만약 스토리보드를 사용한다면 유일한 의존성 주입 방법이다.
- Method Injection 의존성을 파라미터로 주는 메소드를 정의한다. Serializer는 DataManager 안에 변수를 가지고 있지 않다.그렇기 때문에 DataManager 전체에서 Serializer를 통제할 수 없고 메소드 내에서만 통제가 가능하다.그렇지만 우리가 선택한 Serializer의 타입에 의존함으로써 유연성을 제공한다.
5. 의존성 주입 라이브러리 Swinject
- 컨테이너 기반
- register 메서드로 사용할 객체 등록
- resolve로 객체 꺼내온다.
let container = Container()
container.register(Animal.self) { _ in Cat(name: "Mimi") }
container.register(Person.self) { r in
PetOwner(pet: r.resolve(Animal.self)!)
}
// 사용
let person = container.resolve(Person.self)!
person.play() // prints "I'm playing with Mimi."
6. 참고자료
'iOS' 카테고리의 다른 글
[iOS] Combine 프레임워크 (0) | 2025.01.31 |
---|---|
[Swift] 값형식(Value Type) 과 참조형식(Reference Type) (0) | 2024.05.07 |