Swift- Dependency Injection

내승현·2023년 12월 13일
0

Swift

목록 보기
13/14

✅ 의존성 주입은 swift에서만 등장하는 용어는 아니다.
거의 모든 객체 지향 프로그래밍 언어에서 찾아볼 수 있지만 , 아래는 Swift 예시다.

Dependcy, 의존성이란 ?

객체 지향 프로그래밍에서 Dependency, 의존성은 서로 다른 객체 사이에 의존 관계가 있다는 것을 말한다. 즉, 의존하는 객체가 수정되면, 다른 객체도 영향을 받는다는 것이다.

예를 들어 아래의 코드를 보자.

import UIKit

struct Eat {
    func coffee() {
        print("아메리카노")
    }

    func meal() {
        print("피자")
    }
}

struct Person {
    var todayEat: Eat
    
    func coffee() {
        todayEat.coffee()
    }
    
    func meal() {
        todayEat.meal()
    }
}

Person 객체는 Eat 객체를 인스턴스로 사용하고 있으므로, Eat 객체에 의존성이 생긴다.
만약 이때, Eat 객체에 중요한 수정이나 오류가 발생한다면, Person 객체도 영향을 받을 수 있다.

의존성을 가지는 코드가 많아진다면, 재활용성이 떨어지고 매번 의존성을 가지는 객체들을 함께 수정해주어야 한다는 문제가 발생한다.

이러한 의존성을 해결하기 위해 나온 개념이 바로 Dependency Injection, 의존성 주입이다!!!!!

Injection, 주입이란 ?


injection, 주입은 외부에서 객체를 생성해서 넣는 것을 의미한다.

class Eat:Menu {
    var coffee: String
    var meal: String
    
    init(coffee: String, meal: String) {
        self.coffee = coffee
        self.meal = meal
    }
    
    func printCoffee() {
        print("아메리카노")
    }
    
    func printMeal() {
        print("피자")
    }
}

let menu = Eat(coffee: "아메리카노", meal: "피자")

위 코드와 같이 생성자(init = 이니셜라이저)등을 활용해서 외부에서 주입할 수 있다.

Dependency Injection, 의존성 주입!


그렇다면 의존성 주입을 하는 이유는 무엇일까?

  • Unit Test가 용이해진다.
  • 코드의 재활용성을 높여준다
  • 객체 간의 의존성(종속성)을 줄이거나 없앨 수 있다.
  • 객체 간의 결합도를 낮추면서 유연한 코드를 작성할 수 있다.

그렇다면 내부에서 만든 객체를 외부에서 넣어서 의존성을 주입해보자.
하지만 전에 의존 관계 역전 법칙을 알아야한다.

Dependency Inversion Principle, 의존 관계 역전 법칙


DIP, 의존 관계 역전 법칙은 객체 지향 프로그래밍 설계의 다섯가지 기본 원칙(SOLID) 중 하나이다. 추상화 된 것은 구체적인 것에 의존하면 안되고 구체적인 것이 추상화된 것에 의존 해야한다.

즉, 구체적인 객체는 추상회된 객체에 의존 해야한다는 것이 핵심 !!!!이다ㅎㅎ
(이런 자세한 정보는 나도 이번에 공부하면서 알게된 ,,, 멀고도 머네요 ,,,)

Swift에서 추상화된 객체는 Protocol이 있다.
우리는 이 protocol을 활용해서 의존성 주입을 구현해보자

우선 protocol을 활용해서 추상적인 객체를 만들어야한다.
Menu라는 ProtocolprintCoffee()printMeal() 함수를 가지고 있다.

protocol Menu {
    func printCoffee()
    func printMeal()
}

이후 Eat클래스는 Menu Protocol을 채택한 후, Protocol에 정의한 함수를 실체화 시켜준다.

class Eat: Menu {
    var coffee: String
    var meal: String
    
    init(coffee: String, meal: String) {
        self.coffee = coffee
        self.meal = meal
    }
    
    func printCoffee() {
        print("아메리카노")
    }
    
    func printMeal() {
        print("피자")
    }
}

이제부터 중요한 부분이 나온다.
기존의 방식과 다르게 todayEat 변수는 추상적인 객체인 Menu 타입에 의존하게 된다.

여기서 changeMenu 함수를 활용해서 의존성 주입을 시킬 수 있다.

struct Person {
    var todayEat: Menu
    
    func printCoffee() {
        todayEat.printCoffee()
    }
    
    func printMeal() {
        todayEat.printMeal()
    }
    
    mutating func changeMenu(menu: Menu) {
        self.todayEat = menu
    }
}

이렇게 구현한다면 Eat객체와 Person 객체는 거의 독립적인 객체가 된다.
Eat 객체를 수정하거나 Person을 수정한다고 해서 상대 객체를 함께 수정해야 하는 문제를 방지할 수 있다.

let menu = Eat(coffee: "아메리카노", meal: "피자")
let anotherMenu = Eat(coffee: "라떼", meal: "햄버거")

var suhshin = Person(todayEat: menu)

suhshin.printCoffee() // print 아메리카노
suhshin.changeMenu(menu: anotherMenu)
suhshin.printCoffee() // print 라떼
profile
아토언니의 프론트엔드 개발자로서의 기록

0개의 댓글