Design Pattern

DI(Dependency Injection)

motosw3600 2022. 1. 19. 17:23

DI(Dependency Injection)이란?

  • 의존성을 객체 외부에서 주입해주는 형식
  • SOLID원칙중 DIP(의존성 역전 원칙)으로 특정 모듈에 의존하지 않고 의존성이 역전됨을 의미
  • 상위모듈은 의존성 주입을 통해 하위 모듈에 의존하지 않고 구조 설계 가능

Dependency Injection이 적용되지 않은 경우

 

class Foo {
    private var bar: Bar
    
    init() {
        self.bar = Bar()
    }
}

 

 

Dependency Injection이 적용된 경우

 

class Foo {
    private var bar: Bar
    
    init(bar: Bar) {
    	self.bar = bar
    }
}

 

 

DI가 필요한 이유

  • Interface를 통해 구체타입에 의존하지 않고(결합도↓) 상황에 따라 변경가능하고 단위 테스트시 간결함을 유지
  • 의존성 파라미터를 생성자에서 작성하지 않고 주입받음으로써 유연한 프로그래밍 가능

DIContainer 예시(+with Coordinator)

 

DIContainer에서 Coordinator 주입

 

DIContainer에서 (ViewController, viewModel, usecase..) dependencies self로 정의

 

class DIContainer {
    func createMainCoordinator(navigationController: UINavigationController) -> MainCoordinator {
        return MainCoordinator(navigationController: navigationController, dependencies: self)
    }
}

extension DIContainer: MainCoordinatorDependencies {
    func createHomeViewController(actions: HomeViewModelActions) -> UIViewController {
        let viewModel = HomeViewModel(actions: actions)
        return HomeViewController(viewModel: viewModel)
    }
    
    func createDetailViewController() -> UIViewController {
        return DetailViewController()
    }
}

 

 

DIContainer에서 Coordinator를 만들어서 주입

 

let diContainer = DIContainer()
let navigationController = UINavigationController()
let mainCoordinator = diContainer.createMainCoordinator(navigationController: navigationController)

 

  • 화면이동 Process

 

Coordinator에서 화면이동 핸들러 정의(showDetailViewController)

 

protocol MainCoordinatorDependencies {
    func createHomeViewController(actions: HomeViewModelActions) -> UIViewController
    func createDetailViewController() -> UIViewController
}

final class MainCoordinator {
    private var navigationController: UINavigationController?
    private let dependencies: MainCoordinatorDependencies
    
    init(navigationController: UINavigationController, dependencies: MainCoordinatorDependencies) {
        self.navigationController = navigationController
        self.dependencies = dependencies
    }
    
    func start() {
        let actions = HomeViewModelActions(showDetail: showDetailViewController)
        let homeViewController = self.dependencies.createHomeViewController(actions: actions)
        self.navigationController?.pushViewController(homeViewController, animated: true)
    }
    
    private func showDetailViewController() {
        let detailViewController = dependencies.createDetailViewController()
        self.navigationController?.pushViewController(detailViewController, animated: true)
    }
}

 

 

viewModel에 Actions주입

 

struct HomeViewModelActions {
    let showDetail: () -> Void
}

protocol HomeViewModelInput {
    func didTappedNextButton()
}

protocol HomeViewModelOutput { }

protocol HomeViewModelIO: HomeViewModelInput, HomeViewModelOutput { }

final class HomeViewModel: HomeViewModelIO {
    private let actions: HomeViewModelActions
    
    init(actions: HomeViewModelActions) {
        self.actions = actions
    }
}

extension HomeViewModel {
    func didTappedNextButton() {
        actions.showDetail()
    }
}

 

 

 

참고

https://ali-akhtar.medium.com/ios-dependency-injection-using-swinject-9c4ceff99e41 

https://ios-development.tistory.com/711

'Design Pattern' 카테고리의 다른 글

Delegate Pattern  (0) 2021.12.14
Clean Architecture  (0) 2021.12.10
MVC Pattern  (0) 2021.12.10