VB のたまご

作成日: 2017/05/14, 更新日: 2017/05/14



依存性が注入されている状態

  •  これ以降、毎回 Prism ライブラリを使うため、WPF アプリケーションやクラスライブラリを作成後に、 NuGet パッケージの管理から「Prism.Unity」を検索して、関連物一式をプロジェクトにインストールして利用しています。

  • スポンサーリンク


  •  ここでは、DI(Dependency Injection、ディペンデンシーインジェクション、依存性の注入)と、 DIコンテナの1つである UnityContainer(ユニティコンテナ)について学習します。

  •  さて、唐突ですが以下のようなプログラムを見てみましょう。

  • イメージ
  •  実際にはコンソールアプリケーションで以下のように作成しています。

  • ' 日本人
    Public Class JapaneseSpeaker
    
        Public Sub Speak()
    
            Console.WriteLine("こんにちは!")
    
        End Sub
    
    End Class
    

    ' 会議
    ' 日本人しか話すことができない。Speak メソッドの中で、JapaneseSpeaker クラスに依存している
    Public Class Meeting
    
        Public Sub New()
    
        End Sub
    
        Public Sub Speak()
    
            Dim speaker = New JapaneseSpeaker
            speaker.Speak()
    
        End Sub
    
    End Class
    

    Module Module1
    
        Sub Main()
    
            ' 会議で話す日本人
            Dim myMeeting = New Meeting
            myMeeting.Speak()
    
            Console.Read()
        End Sub
    
    End Module
    

  •  会議の場で、従業員同士で議論をするプログラムです。ある日、国際会議ができるように修正しようと決まったとします。 すると、海外の方も会議に参加して議論することになりますので、新しいクラスを作成することと、会議クラスの拡張が必要があります。 まずは、アメリカの英語圏の方が参加できるようにすることにします。

  • ' アメリカ人
    Public Class AmericanSpeaker
    
        Public Sub Speak()
    
            Console.WriteLine("Hello!")
    
        End Sub
    
    End Class
    

    ' 会議
    Public Class Meeting
    
        Public Sub New()
    
        End Sub
    
        Public Sub Speak()
    
            Dim speaker1 = New JapaneseSpeaker
            speaker1.Speak()
    
            Dim speaker2 = New AmericanSpeaker
            speaker2.Speak()
    
        End Sub
    
    End Class
    

  •  簡単に考えると、新しいクラスを作成して、会議クラスに呼び出し追加すれば良さそうですが、 このような構成では、各国の方が増えるたびにメンテナンス量が増えてきそうです。参加・不参加はよくあることです。 このことから会議クラスは、仕様変更の影響を受けやすい、仕様変更に弱いことが分かると思います。

  •  この時、「会議クラスは、日本人クラス、アメリカ人クラスに依存している」状態と言えます。 参加・不参加によって、都度修正が必要ですからね。

  • スポンサーリンク


  •  依存はなるべく避けたいものです。依存が無ければ、会議クラスは修正の嵐から脱却することができます。 どうすればいいかというと、日本人やアメリカ人は、人間(地球人)という共通点がありますので、人間インターフェースを用意します。

  •  より抽象化して(継承先の複数のクラスをまとめて)扱うという考え方です。 これなら、地球に住む他の国の方でも人間インターフェースを継承することになるので、うまくいきそうです。

  • イメージ
  •  会議クラスでは、まず内部で各国の人のインスタンス生成することを止めます。インスタンスは外部からもらってくることにします。 この時、いろいろな国の方が議論できるように、人間インターフェースをもらってくることにします。

  •  注入って難しい事言っていますが、要するに、コンストラクタやメソッド呼び出し時に引数経由でインスタンスをもらう、 プロパティとかの Public なメンバーにインスタンスを渡してもらうことを言います。

  •  これをソースにすると以下のようになります。

  • ' 各国共通インターフェース
    Public Interface ISpeaker
    
        Sub Speak()
    
    End Interface
    

  •  (追記)記事を書くまで気づきませんでしたが、アクセス修飾子が Private になっているのに、インターフェースに渡すと外部からメソッドを呼び出すことができます。 インターフェースの強制力はすごいですね。混乱してしまうので、みなさんが書くときには、インターフェース継承したメンバーには、Public を付けた方がいいと思います。

  • ' 日本人
    Public Class JapaneseSpeaker
        Implements ISpeaker
    
        Private Sub Speak() Implements ISpeaker.Speak
    
            Console.WriteLine("こんにちは!")
    
        End Sub
    
    End Class
    

    ' アメリカ人
    Public Class AmericanSpeaker
        Implements ISpeaker
    
        Private Sub Speak() Implements ISpeaker.Speak
    
            Console.WriteLine("Hello!")
    
        End Sub
    
    End Class
    

    ' 会議
    Public Class Meeting
    
        Public Sub New()
    
        End Sub
    
        Public Sub Speak(speaker As ISpeaker)
    
            speaker.Speak()
    
        End Sub
    
    End Class
    

    Module Module1
    
        Sub Main()
    
            ' 会議で話す各国の人
            ' 各国の人のインスタンスを外部から注入
            Dim myMeeting = New Meeting
            myMeeting.Speak(New JapaneseSpeaker)
            myMeeting.Speak(New AmericanSpeaker)
    
            Console.Read()
        End Sub
    
    End Module
    

  •  このように、内部にある依存を外部に出して、外部からインスタンスを注入する実装パターンを、DI(Dependency Injection、依存性の注入)と言います。

  • イメージ

  •  このサンプルの場合だと、インターフェース・インジェクションと言います。 他にも、コンストラクタ・インジェクション、(プロパティの)セッター・インジェクションがありますが割愛します。