Swiftで見るDI(依存性注入)とは?実装方法やサンプルコード

この記事からわかること

  • DI(Dependency Injection:依存性注入)とは?
  • Swiftで見るDIについて
  • DIの種類
  • 依存関係とは?
  • Interface Injection/Constructor Injection/Setter Injectionとは?

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

Wiki:依存性の注入

アプリ開発で「DI」と言う言葉に触れるようになり、実際に意識した開発を心掛けたいと思ったので自分なりにまとめていきたいと思います。

間違っている点や誤解を招く表現があるかも知れませんが、何かありましたら教えていただけると嬉しいです。

DI(Dependency Injection:依存性注入)とは?

DIはDependency Injectionの略称であり日本語では依存性注入という意味で、アプリ開発などのオブジェクト指向型のソフトウェア開発における基本的な考え方や設計原則を表現しパターン化したデザインパターンの1つになるようです。

デザインパターンにも様々な種類がありますがその中でもDIの特徴は「依存関係をオブジェクト外に持たせて外部から注入するような設計にする」です。

依存関係とは?

そもそも依存関係とはオブジェクト同士が依存している関係のことです。ここでいうオブジェクトはクラスや構造体、メソッドなども当てはまります。そして結合が強い状態のことを密結合と呼んだりします。

一度例を見てみます。以下にはUserクラスとActionGameクラスが定義されていますがここで依存関係が生まれています。

class User {
    
  var stamina:Int = 20
  
    func playGame(){
        let actionGame = ActionGame()
        if actionGame.requiredStamina <= self.stamina {
            print("Playing")
            stamina -= actionGame.requiredStamina
        }else{
            print("Out of Stamina...")
        }
    }
}

class ActionGame {
    var requiredStamina:Int = 10
}

let user = User()
user.playGame()
print(user.stamina) 
// Playing
// 10

Userクラスの中でActionGameクラスがインスタンス化されているため、UserクラスはActionGameクラスが存在しないとクラスとしての機能を保てません。これがまさしく依存している状態です。これでもコードは動作するし問題がないといえばそれまでです。

では新しくRacingGameを増やすことを考えてみます。今のままだとUserクラス内に新しくメソッドを追加するしかなくなってしまいます。これでは拡張性がありません。なのでprotocolを使用して抽象的なオブジェクトを作り、それをUserクラスに注入するように変更してみます。

class User {
    
  var stamina:Int = 20
  
    func playGame(game: Game){
        if game.requiredStamina <= self.stamina {
            print("Playing")
            stamina -= game.requiredStamina
        }else{
            print("Out of Stamina...")
        }
    }
}

class ActionGame: Game {
    let requiredStamina:Int = 10
}

class RacingGame: Game {
    let requiredStamina:Int = 5
}

protocol Game {
    var requiredStamina:Int { get }
}

let user = User()
user.playGame(game: ActionGame())
user.playGame(game: RacingGame())
print(user.stamina) 
// Playing
// Playing
// 5

依存がなくなったわけではないですが依存度はだいぶ軽減されたかと思います。これが完璧にDIのサンプルとして正しいわけではないと思いますがDIの雰囲気は掴めたかと思います。

導入するメリット

DIを導入すれば必ずメリットが生まれる訳ではありません。規模や環境によって導入するメリットがあるかないかは考える必要があるかと思います。そこはさておき、DIを導入することで生まれるメリットをまとめてみます。

メリット

オブジェクト同士の結合度が低下することで再利用性や拡張性がと高まります。また依存関係を外部から受け取る方式にすることでモックやスタブへの置き換えがしやすくなり、結果テストの効率性が向上します。

DIの種類

プログラムに依存性を注入する方法としてDIでは3種類の方法が挙げられています。

Interface Injection(インターフェイスインジェクション)

インターフェイス(プロトコル)を用意しそれに準拠させることで専用のインターフェースを介して注入。最初にやったのはこれに近いです。

Constructor Injection(コンストラクタインジェクション)

コンストラクタ(イニシャライザ)としてクラスをインスタンス化して注入。プロパティとして保持する

Setter Injection(セッターインジェクション) or Field Injection(フィールドインジェクション)

プロパティ内に変数を定義しておきsetterメソッド経由でインスタンス化して注入。オブジェクトのインスタンスが作成された後に依存関係を注入できる

DIを意識した開発

DIについて長々と色々な説明がありましたが、結局のところなんなのか分かりにくい部分が多いです。私的にとりあえず以下のポイントに気をつけていればDIを意識した開発(あくまで意識したです)ができると思います。

この記事を書くにあたって wikipediaの記事を参考にしましたが意外と分かりやすかったです。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index