DI (Dependency Injection)
2024. 7. 15. 17:36ㆍClean Architecture
개념
클래스 내부에서 필요한 객체의 인스턴스를 외부에서 생성한뒤 이니셜라이저 또는 setter를 통해 주입 받는것
외부에서 객체가 필요한것을 전달해주는것
- 의존성 주입의 의도는 의존성을 분리하기 위해서 의존성 주입 방법 사용
- 의존성 주입 + 의존성 분리의 조건을 만족해야함
- 클래스가 의존성을 해결하려 시도 X→ DI 컨테이너는 필요한 객체의 인스턴스를 만든후 의존성 설정
- DI를 통해 생성, 사용간의 분리가 가능
- testable한 코드 확립이 가능
- 이니셜라이저의 타입은 프로토콜을 활용해 내부에서는 프로토콜 메서드 사용
- 제어 역전 기법을 의존성 관리에 적용한 메커니즘
DI 이해를 위한 개념
- 의존성
- 주입
- 의존성 분리
의존성
서로 다른 객체 사이의 의존 관계를 가지는 것
- 면접에서 질문시 “의존성이란 클래스간의 연관 되어 있는 관계 “ 라고 답할것 같다.
Ex) 의존성
class Man {
let name: String
init(name: String) {
self.name = name
}
}
class Person {
let person: Man
init() {
self.person = Man(name: "동진")
}
}
let wdj = Person()
print(wdj.gender.name)
→ Man 클래스의 name 프로퍼티 타입 변경시 Person에서 Man 타입의 프로퍼티인 gender에 영향이 간다.
→ Person이 Man에 의존
주입 Injection
외부에서 객체를 생성해서 주입 with 생성자
Ex) 주입
class Person {
let name: string
init(name: String) {
self.name = name
}
}
let wdj = Person(name: "원동진")
의존성 주입
EX) 의존성 주입
class Man {
let name: String
init(name: String) {
self.name = name
}
}
class Person {
let person: Man
init(person: Man) {
self.person = person
}
}
let man = Man(name: "동진")
let wdj = Person(person: man)
print(wdj.person.name)
의존성이 주입시킨 것으로 DI라고 부르지 않음 → 의존성 분리의 조건을 만족하여야 DI라고 한다.
의존성 분리
의존성 분리의 조건 만족 → DI
- 의존성 분리는 의존관계 역전의 원칙 (DIP)기반으로 분리를 실행
- DIP
- 의존 관계를 맺을때, 변화하기 쉬운것보다 변화하기 어려운것에 의존
- 변화하기 어려운 것이란 추상 클래스나 인터페이스, 변화하기 쉬운것은 구체화된 클래스
→ Protocol 사용
개선된 의존성 = 의존성 분리의 조건을 만족
프로토콜(Protocol)을 활용하여 의존성 분리시키고 의존관계를 역전
Ex) DI
protocol Gender {
var name: String {get set}
}
class Man: Gender {
var name :String
init(name: String) {
self.name = name
}
}
class Person {
let person: Gender
init(person: Gender) {
self.person = person
}
}
let aPerson = Man(name: "동진")
→ 프로토콜의 name의 자료형 변경시 Gender을 가지고 있는 클래스에 에러 발생 즉 → 제어 주체인 프로토콜을 파악하면 해당 프로토콜을 준수하는 모든 클래스를 제어하고 분석하기 쉬어짐
→ 위의 코드중 만약 Woman을 추가하고 싶다면
Ex) DI의 장점인 확장
class Woman: Gender {
var name :String
init(name: String) {
self.name = name
}
}
class Person {
let person: Gender
init(person: Gender) {
self.person = person
}
}
let aGender = Man(name: "동진")
let bGener = WoMan(name: "동순")
let aPerson = Person(person: aGender) // bGender 도 대입가능
- 외부에서 언제든지 새로운 객체로 교체 가능, 확장용이
- Gender 프로토콜을 채택한 모든 타입들이 할당가능
의존성 주입 장단점
장점
- 객체간의 의존성 ⬇️, 코드의 재활용성/ 확장성 ⬆️
- 객체 간의 결합도 ⬇️, 유연한 코드/프로그램 작성 가능
- 유지 보수 쉬워짐
단점
- 책임 분리로인한 클래스 수 증가 복잡성 ⬆️
- 주입된 객체들에 관한 코드 추적이 어려움 → MVVM패턴을 코드를 읽을 때 추적하기 어려운 경험이 있음
- 러닝 커브 ⬆️
- 프레임워크에 대한 의존도 ⬆️
💡 의존성 주입에 대한 생각
단순하고 유지보수,확장성이 없는 프로그램은 의존성 주입은 시간을 더 뺏긴다고 생각한다. 참고로 의존성 주입을 하지 않고도 지금까지 개발을 잘 진행 해왔음..
많은 기능과 복잡한 코드에 대한 전체적인 틀이 없어서 기능 확장할경우 코드의 전체전인 부분을 전부 고쳐야되는 현상이 발생 → 현재 진행중인 프로젝트 리팩토링하면서 DI를 적용후 차이점 적을 예정
참고
Swift 의존성 주입 (Dependency Injection)