Person 이라는 객체는 Drink객체를 인스턴스로 사용하고 있으므로, Drink 객체에 의존성이 생겨요
만약 이때 Drink 객체에 중요한 수정이나 오류가 발생하게 된다면 어떻게 될까요?
당연히 Person 이라는 객체에도 영향을 받을 수 있습니다.
의존성을 가지는 코드가 많아진다면 어떻게 될까요?
재활용성이 떨어지고 매번 의존성을 가지는 객체들을 함께 수정해주어야 한다는 문제가 발생하겠죠?
이러한 의존성을 해결하기 위해 나온 개념이 바로 의존성 주입(Dependency Injection) 입니다.
What is Injection ( 주입 ) ?
Injection은 내부가 아닌 외부에서 객체를 생성해서 넣어주는 것을 의미해요.
class Eat: Menu {
var coffee: String
var water: String
init(coffee: String, water: String) {
self.coffee = coffee
self.water = water
}
func printCoffee() {
print("아메리카노")
}
func printWater() {
print("물")
}
}
let menu = Eat(coffee: "아메리카노", water: "물")
다음과 같이 객체를 참조할때 생성자를 활용해서 외부에서 주입할 수 있어요.
그럼 의존성과 주입에 대해 알아봤으니까 의존성 주입에 대해 알아볼까요?
Dependency Injection ( 의존성 주입 )
클래스 내부에서 의존하는 객체를 생성하는 것이 아니라,
외부에서 생성한 후 의존하는 객체를 전달받아 사용하는 디자인 패턴이에요.
이를 통해 객체간의 결합도를 낮추고 유연하고 확장성 있는 설계가 가능하도록 도와줍니다.
크게 4가지 방법으로 사용할 수 있습니다.
1. 생성자 주입
2. 프로퍼티 주입
3. 메서드 주입
4. 인터페이스 주입
1. 생성자 주입
생성자를 통해 파라미터 값으로 필요한 의존성을 받아 객체를 생성합니다.
보통 초기에 꼭 필요한 데이터나 객체가 있을 때 사용 됩니다.
class Engine {
func start() {
print("엔진 가동")
}
}
class Car {
private let engine: Engine
init(engine: Engine) {
self.engine = engine
}
func start() {
engine.start()
print("차가 출발합니다.")
}
}
let engine = Engine()
let myCar = Car(engine: engine)
myCar.start()
// 엔진 가동
// 차가 출발합니다.
2. 프로퍼티 주입
객체를 생성한 후 프로퍼티를 통해 의존성을 전달하는 방식입니다.
class Engine {
func start() {
print("엔진 가동")
}
}
class Car {
var engine: Engine?
func start() {
engine?.start()
print("차가 출발합니다.")
}
}
let engine = Engine()
let myCar = Car()
// Car 인스턴스의 engine 프로퍼티에 Engine 인스턴스 할당
myCar.engine = engine
myCar.start()
// 엔진 가동
// 차가 출발합니다.
3. 메서드 주입
의존성이 필요한 메서드를 호출할 때, 해당 메서드에 파라미터 값에 의존성을 전달하는 방식입니다.
class Engine {
func start() {
print("엔진 가동")
}
}
class Car {
// Engine 클래스를 파라미터로 전달받음
func start(with engine: Engine) {
engine.start()
print("차가 출발합니다.")
}
}
let engine = Engine()
let myCar = Car()
// Engine 클래스의 인스턴스를 전달함
myCar.start(with: engine)
// 엔진 가동
// 차가 출발합니다.
4. 인터페이스 주입
일단 인터페이스란 객체와 객체 사이의 상호작용을 정의하는 추상적인 개념이에요.
Swift에서는 보통 Protocol을 이용해 추상화 시켜줍니다.
객체의 내부 구조나 구현 방식에 관계없이 외부에서 객체를 다룰 수 있게 도와줘요
// 프로토콜 정의
protocol EngineProtocol {
func start()
}
// 하위 모듈 - 프로토콜 채택
class Engine: EngineProtocol {
func start() {
print("엔진 가동")
}
}
// 상위 모듈 - 생성 시 프로토콜을 파라미터로 받음
class Car {
private let engine: EngineProtocol
init(engine: EngineProtocol) {
self.engine = engine
}
func start() {
// 프로토콜을 이용해 하위 모듈의 메서드 사용
engine.start()
print("차가 출발합니다.")
}
}
let engine = Engine()
let myCar = Car(engine: engine)
myCar.start()
// 엔진 가동
// 차가 출발합니다.
그럼 여기서 인터페이스 주입 패턴을 이용해서 전기차로 개조를 시켜보면 어떻게 될까요?
상위 모듈의 코드를 수정하지 않고도 확장이 용이해져 깔끔하게 수정할 수 있습니다.
// 프로토콜 정의
protocol EngineProtocol {
func start()
}
// 하위 모듈 - 가솔린 엔진
class GasolineEngine: EngineProtocol {
func start() {
print("가솔린 엔진 가동")
}
}
// 하위 모듈 - 전기 모터 (추가)
class ElectricMotor: EngineProtocol {
func start() {
print("전기모터 가동")
}
}
// 상위 모듈
class Car {
private let engine: EngineProtocol
init(engine: EngineProtocol) {
self.engine = engine
}
func start() {
// 프로토콜을 이용해 하위 모듈의 메서드 사용
engine.start()
print("차가 출발합니다.")
}
}
let gasoline = GasolineEngine()
let motor = ElectricMotor()
let myGasolineCar = Car(engine: gasoline)
let myElectricCar = Car(engine: motor)
myGasolineCar.start()
// 가솔린 엔진 가동
// 차가 출발합니다.
myElectricCar.start()
// 전기모터 가동
// 차가 출발합니다.
Intro
이번에는 의존성 주입(Denpendency Injection)에 대해서 공부하고 정리해봤습니다. 주제의 선정 이유는 최근 본 면접에서 의존성 주입에 대한 질문을 받았는데 명확하게 답변을 하지 못해 자세히 알아보려고 합니다.
What is Dependency ( 의존성 ) ?
객체 지향 프로그래밍에서 Dependency 즉 의존성은 서로 다른 객체 사이에 의존 관계가 있다는 것을 말해요. 즉 의존하는 객체가 수정되면 다른 객체에도 영향을 받는 것을 말해요.
Person 이라는 객체는 Drink객체를 인스턴스로 사용하고 있으므로, Drink 객체에 의존성이 생겨요 만약 이때 Drink 객체에 중요한 수정이나 오류가 발생하게 된다면 어떻게 될까요? 당연히 Person 이라는 객체에도 영향을 받을 수 있습니다. 의존성을 가지는 코드가 많아진다면 어떻게 될까요? 재활용성이 떨어지고 매번 의존성을 가지는 객체들을 함께 수정해주어야 한다는 문제가 발생하겠죠? 이러한 의존성을 해결하기 위해 나온 개념이 바로 의존성 주입(Dependency Injection) 입니다.
What is Injection ( 주입 ) ?
Injection은 내부가 아닌 외부에서 객체를 생성해서 넣어주는 것을 의미해요.
다음과 같이 객체를 참조할때 생성자를 활용해서 외부에서 주입할 수 있어요. 그럼 의존성과 주입에 대해 알아봤으니까 의존성 주입에 대해 알아볼까요?
Dependency Injection ( 의존성 주입 )
클래스 내부에서 의존하는 객체를 생성하는 것이 아니라, 외부에서 생성한 후 의존하는 객체를 전달받아 사용하는 디자인 패턴이에요. 이를 통해 객체간의 결합도를 낮추고 유연하고 확장성 있는 설계가 가능하도록 도와줍니다. 크게 4가지 방법으로 사용할 수 있습니다. 1. 생성자 주입 2. 프로퍼티 주입 3. 메서드 주입 4. 인터페이스 주입
1. 생성자 주입
생성자를 통해 파라미터 값으로 필요한 의존성을 받아 객체를 생성합니다. 보통 초기에 꼭 필요한 데이터나 객체가 있을 때 사용 됩니다.
2. 프로퍼티 주입
객체를 생성한 후 프로퍼티를 통해 의존성을 전달하는 방식입니다.
3. 메서드 주입
의존성이 필요한 메서드를 호출할 때, 해당 메서드에 파라미터 값에 의존성을 전달하는 방식입니다.
4. 인터페이스 주입
일단 인터페이스란 객체와 객체 사이의 상호작용을 정의하는 추상적인 개념이에요. Swift에서는 보통 Protocol을 이용해 추상화 시켜줍니다. 객체의 내부 구조나 구현 방식에 관계없이 외부에서 객체를 다룰 수 있게 도와줘요
그럼 여기서 인터페이스 주입 패턴을 이용해서 전기차로 개조를 시켜보면 어떻게 될까요? 상위 모듈의 코드를 수정하지 않고도 확장이 용이해져 깔끔하게 수정할 수 있습니다.
의존성 주입의 사용 이유는?