LoginSignup
3
1

More than 5 years have passed since last update.

Dependency Injection(依存の注入)とは?

Posted at

自分が理解したいためにまとめました!間違いがあればぜひご指摘を。

1. Dependency Injection(DI)ってなんやねん。

意味を訳すと、Dependency = 依存で、
Injection = 注入、注射するです。つまり、
「依存していた部分を、外から注入すること」by @hshimoさん
つまり、外からオブジェクトを受け取ることです。

2. DIが便利なわけ / 使いたい理由

*@hshimo さんから言葉をお借りしてます

柔軟性がない -> 決め打ちなので、柔軟性がなくカスタマイズしにくい
テストしにくい -> 外から動的に動作を変更できないので、テストしづらい

ってイキナリ言われても解らんですよね。そこで例えを使って考えましょう。

3. 例で考える

たとえば、ドクターがいて、ナースさんがいて、カルテがあったら、普通はドクターがカルテを書いて、ナースさんに渡してそれを元に患者に対応しますよね?(DI後)

でも、医者がカルテ作成を全部ナースさんに丸投げしたらどうなるでしょうか? ナースさんはいちいちドクターに患者の状況を聞いてから、カルテを作成しないと行けないです。(DI前)

こうなると、ナースさんの仕事が増えてすごく大変。しかもカルテをドクターが直したい、となったら、ナースさんはまたイチから作成しないといけません。(DI前)

Screen Shot 2017-07-16 at 12.06.57 AM.png

DI前のコード

protocol Carte {}
class Doctor{
   func assignNurse() -> Nurse{
      var nurse = Nurse()
      return nurse
   }
}

class Nurse {
    let carte: Carte

    init() {
        carte = Carte()
    }
}
main.swift
doctor.assignNurse()

DI後コード

class Carte {}
class Doctor{
  func makeCarte() -> Carte{
    var carte = Carte()
    return carte
  }
}

class Nurse {
    let carte: Carte

    init(_ carte: Carte) {
        self.carte = carte
    }
}
main.swift
var carte = doctor.makeCarte()
var nurse = Nurse(carte)

DI後コードでは、NurseクラスはCarteをinit(作成してない!)
そして外からcarteオブジェクトを注入にしているので、carteに変更があった場合、Nurseの中身は書き換えなくてもいいので、テストが楽。

DIがを使いたい理由を簡単に説明すると、
一つのクラスが仕事を持ちすぎているので(クラス依存)、スムーズに事が進むように、仕事を分担する、という感じで。ナースさんはカルテの中身を知りたいけど、作成方法は一切知らなくてもいい、という感じです。

え、例えとコードが微妙??ごめんなさい。

4. 色々なところで使うDependency Injection

1. Viewcontrollerから別なViewControllerを開くとき

ViewController.swift
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if getIndexPathForSelectedCell() != nil {
            let newView = segue.destination as! DetailViewController
            newView.folderIndexPath = getIndexPathForSelectedCell()!
            newView.dataSource = self.dataSource
        }
    }

DetailViewController.swift
    var folderIndexPath:IndexPath
    var dataSource:DataSource

    init(_ folderIndexPath:IndexPath, _ dataSource:DataSource) {
        self.folderIndexPath = folderIndexPath
        self.dataSource = dataSource
    }

ここでは、DataSourceクラスはViewControllerのどこかでinitializeされていて、それをDetailViewControllerにパスしています。

2. AppDelegateにあらかじめDIしておく

AppDelegate.swift
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.


        //dependency injection
        let rootViewController = window?.rootViewController as! UINavigationController
        let photoViewController = rootViewController.topViewController as! PhotoViewController

        photoViewController.store = PhotoStore()

        return true
    }
PhotoViewController.swift
    var store:PhotoStore!

ここではAppDelegateから画面に現れる最初のViewControllerを指定してます。いつもはViewControllerが勝手に出ますが、ここではPhotoViewControllerを出すように指示しています。
そのほかに、PhotoStoreクラスのinitializeもここで行なって、PhotoViewControllerにDI(注入)しています。

参考!
猿でも分かる! Dependency Injection: 依存性の注入
Dependency Injection in Swift

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1