의존성 주입이란 무엇일까?
의존성 주입은 거의 모든 객체지향 프로그래밍 언어에서 찾아볼 수 있다.
의존성 주입이 무엇을 의미하는지, 왜 필요한지 알아보자.
Dependency는 무엇이냐?
서로 다른 객체 사이에 의존 관계가 있다는 것을 의미
즉, 의존하는 객체가 수정되면, 다른 객체도 영향을 받는다는 것을 의미한다.
예제 코드로 보자.
struct Me {
private let coffee = Coffee()
func startToday() {
self.coffee.drink()
}
}
Me 구조체에서 startToday 메소드를 호출할려면 Coffee 구조체가 필요하다.
이때 Me 구조체는 Coffee구조체의 의존성을 가진다라고 표현한다.
위 코드에서 coffee의 drink 메소드가 삭제되거나 변경되면 Me 구조체의 startToday 메소드도 변경되어야 한다.
즉, 코드의 재사용성이 떨어지고 결합도가 올라간다고 할 수 있다.
Injection은 무엇이냐?
외부에서 객체를 생성해서 넣는 것을 의미한다.
예제 코드로 보자.
struct Me {
private let coffee: Coffee
init(coffee: Coffee) {
self.coffee = coffee
}
func startToday() {
self.coffee.drink()
}
}
let coffee = Coffee()
let me = Me(coffee: coffee)
me.startToday()
코드를 보면 Coffee객체를 외부에서 생성하여 Me 객체가 생성될 때 넣어주고 있다.
이것을 Injection이라고 한다.하지만, 이것 만으로 의존성이 줄어들었다고 할 수 없다.
첫 예제와 같이 Coffee객체의 drink메소드가 삭제되거나 변경된다면 Me객체에서 영향을 받게된다.
위의 예제 코드들 처럼, 의존성을 가진 코드가 많다면 재활용성이 떨어지고, 의존성을 가지는 객체들과 함께 수정해야 하는 문제가 생긴다. 이러한 점을 해결하기 위해 나온 개념이 바로 의존성 주입이다.
의존성 주입으로 생기는 이점
의존 관계 역전 법칙, 줄여서 DIP말한다.
DIP는 객체 지향 프로그래밍 설계의 다섯가지 기본 원칙(SOLID)중 하나이다.
DIP의 핵심은 구체적인 객체는 추상화된 객체에 의존 해야 한다는 것이다.
예제 코드로 보자.
protocol Menu {
func drink()
}
Swift에는 추상화된 객체를 다루는 Protocol이 있다.
Protocol을 사용하여 위와같이 drink메소드를 가진 추상화된 객체를 만들었다.
struct Coffee: Menu {
var coffeeName: String
init(coffeeName: String) {
self.coffeeName = coffeeName
}
func drink() {
print("\(self.coffeeName)를 마신다")
}
}
이후 위와 같이, Coffee 구조체에서 Menu 프로토콜을 채택 후, drink메소드를 실체화 시켜주었다.
struct Me {
var todayCoffee: Menu
func startToday() {
self.todayCoffee.drink()
}
mutating func changeTodayCoffee(menu: Menu) {
self.todayCoffee = menu
}
}
위를 보면 기존의 Coffee 객체에 의존하는 것이 아닌 Menu라는 추상적인 객체에 의존하게된다.
또한, changeTodayCoffee 메소드를 활용해서 의존성을 주입시킬 수 있다.
위의 코드들을 보면 Coffee객체와 Me객체는 거의 독립적인 객체가 된것을 확인할 수 있다.
let coffee = Coffee(coffeeName: "아메리카노")
let anotherCoffee = Coffee(coffeeName: "라떼")
var me = Me(todayCoffee: coffee)
me.startToday()
me.changeTodayCoffee(menu: anotherCoffee)
me.startToday()