프로젝트 준비(DI, IOC)

GomHyeok·2024년 5월 22일

회고록

목록 보기
9/18

소마 프로젝트를 준비하며 기본 베이스 세팅을 위해 학습이 필요하다는 것을 알게 되었다!
그중에서 프로젝트 베이스 세팅을 위해서는 기존 포스트에 작성한 MVVM 모델 아키텍처와 현재 작성하는 DI, IOC에 대하여 학습이 필요하다고 느꼈다.🥹
기존 백엔드를 학습하며 DI와 IOC에 대하여 학습하기는 했지만 조금 부족하다는 생각이 되어 다시 공부하게 되었다.


🍏DI(Dependenct Injection)

DI를 직역하면 의존성 주입이다.
의존성 주입...? 이게 뭔말이지 라는 생각을 할 수 있다.
요약하자면 클래스 내부에서 사용하는 객체를 외부에서 생성한 이후 삽입하는 것(생성자, setter)
이라고 말해도 사실 잘 모르겠다.

😭 다시 이해하기 위해 4가지 개념을 다시 학습할 필요가 있다!
1. 의존성
2. 주입
3. 의존성 분리
4. IOC Container

🍎의존성(Dependency)

아니 그래서 의존성 주입에서 의존성이 뭔데..? 라고 말할 수 있다.

의존성이란 Class A, Class B에 대하여 B의 값 변경에 따라 A의 값도 변경된다면 A는 B에게 의존한다고 말한다.

역시 말로는 정확히 이해하기 힘들다 코드를 확인하며 다시 확인하겠다.
예시 상황으로는 병원을 예시로 만들겠다!

class Doctor {
	let name : Stirng
    init(name : String) {
    	self.name = name
    }
 }
 
 class Nurse {
 	let name : Stirng
    init(name : String) {
    	self.name = name
    }
 }

 class Hospital {
 	let doctor : Doctor
    let nurse : Nurse

    init() {
    	self.doctor = Doctor(name : "David")
        self.nurse = Nurse(name : "Kim")
     }
 }

 let samsung = Hospital()
 print(samsung.doctor.name)
 print(samsung.nurse.name)

해당 코드는 아직은 아무런 문제가 없다. 하지만 여기서 Nurse의 name이 Int로 변경된다면?
samsung의 생성부분에서 오류가 발생할 것이다. 즉 Nurse의 이름만 변경할 뿐인데 Hospital에도 영향을 미치게 된다.

이런 경우가 Hospital이 Docto와 Nurse에 의존한다라고 하는 것이다.
여기서 가장 중요한 부분은 Hospital의 생성자에서 다른 객체의 인스턴스를 생성한다는것!

🍎주입(Injection)

오케이!👌 그럼 의존성 까지는 이해를 완료했다. 그렇다면 주입은?
이것은 바로바로 코드로 확인하자!


class Hospital {
 	let doctor : Doctor
    let nurse : Nurse

    init(doctor : Doctor, nurse:Nurse ) {
	   	self.doctor = doctor
        self.nurse = nurse
    }
}

let doctor = Doctor(nane : "David")
let nurse = Nurse(name : "Kim")
let samsung = Hospital(doctor, nurse)
print(samsung.doctor.name)
print(samsung.nurse.name)

Hospital의 생성자 코드가 변경된다면??
객체의 인스턴스를 외부에서 생성한 뒤 넣어주는 형태가 되었다* 이것이 바로 주입! 이라고 한다.
해당 코드에서는 Nurse의 name이 Int로 변경된다고 해도 Hospital에는 영향을 주지 않는다.
하지만 여전히 nurse와 doctor이 이름이 변경되면 Hospital의 내부 인스턴스에도 영향을 준다.
즉 아직 의존성이 남아있는 것이다! 따라서 아직은 병원이 의사와 간호사에 의존한다고 할 수 있다.

🍎의존성 분리

아니 여기까지 보면 의존성 주입을 다 한거 아니야..? 라고 할 수 있다.
하지만 일반적으로 의존성을 주입했다고 DI를 했다고 생각하지 않는다.

왜냐! 의존성 분리 조건이 지켜지지 않아서 그런 것이다!
그리고 의존성 분리는 DIP(Dependenct Inversion Princple)을 기반으로 분리한다.

🧃DIP(의존 역전의 원칙)은?

  • 의존 관계시에는, 변화하기 어려운 것에 의존해야 한다.
  • 변화하기 어려운 것 = 추상클래스 또는 인터페이스 <-> 반대의 의미는 구체화되어있는 클래스
  • DIP를 만족한다 = 추상클래스 또는 인터페이스와 의존관계를 가진다는 의미!

따라서 Swift에서는 Protocol을 사용할 수 있다! 코드를 통해 살펴보도록 하겠다.

protocol Person: AnyObject {
    var name: String { get }
}

class Doctor: Person {
    let name: String
    init(name: String) {
        self.name = name
    }
}

class Nurse: Person  {
    let name: String
    init(name: String) {
        self.name = name
    }
}

class Hospital {
    let doctor: Person
    let nurse: Person

    init(doctor: Person, nurse: Person) {
        self.doctor = apMost
        self.nurse = nurse
    }
}

let doctor = Doctor(name: "David")
let nurse = Nurse(name: "Kim")
let samsung = Hospital(doctor: doctor, nurse: nurse)

print(samsung.doctor.name)
print(samsung.nurse.name)

여기서 중요한 점은 Hospital이 더이상 각 Class가 아닌 Person 프로토콜에 의존한다는 것이다.
프로토콜의 장점은 프로토콜만 확인하면 해당 *프로토콜을 준수하는 모든 클래스를 분석 제어 가능하다이다.

프로토콜을 사용하지 않고 Name을 모두 Int로 변경해야 한다고 생가해보면.. 그냥 생각하기 싫다!
이러한 과정이 잘 지켜진 경우 class -> 프로토콜로 의존방향이 바뀌었다. = IOC(Inversion Of Control)

지금은 프로토콜이 단순하지만 복잡한 프로토콜이라고 상상해보자! 그러면 기획자가 마구잡이로 코드 변경을 요구한다면..?
우선 멘붕이 오겠지만..😭 조금만 침착해진다면 수정해야 하는 코드가 엄청 줄어든다.
그냥 삽입되는 부분만 변경하면 되는거니까!

🍎IOC Container

의존 역전을 구현하는 프레임워크이다! 즉 제어를 프레임워크에서 진행하는 것이다!
사실 백엔드 공부를 할 때는 Spring Container가 있으니까 그냥 아무생각 없이 사용했지만..
Swift에서는 어떻게 해야하지..? 라고 생각하고 찾아보니 Swinject가 있었다.
따라서 이번 프로젝트에서는 Swinject를 사용해보기로 다짐했다! 하지만 아직 사용 방법은 잘..
프로젝트 세팅을 하며 다시한번 Swinject에 대해 학습해보도록 하겠다!

profile
github : https://github.com/GomHyeok/

0개의 댓글