Xamarin Advent Calendar 2014 第 6 日目は最近話題のゲームエンジンではなく、忘れ去られがちな方の Unity を Xamarin で利用するメリットについてご紹介したいと思います
Unity(ゲームエンジンじゃない方) とは
- 軽量で柔軟性の高い DI コンテナ
- Microsoft patterns & practices チームの進めているプロジェクト成果物のひとつ
DI コンテナとは Dependency Injection(依存関係注入)コンテナのことを指します
Java 界隈の Spring Framework というフレームワークで採用されたのがだいたいの始まりだと記憶しているので、Android 開発者でご存知の方も多いかもしれません
Unity はそんな DI コンテナの1つというわけです
--
Dependency Injection:依存関係注入とは
- 依存関係注入は Inversion of Control(制御の反転)を実現する有力な設計パターンのひとつ
- 外部サービス、データ、手続き処理など依存性のある要素を実行時にクラスの外側から注入することで解決します
- 導入することでクラスインスタンス間の依存性を排除し、疎結合にしやすくなります
通常の設計の場合、外部のサービスクラスを利用するとそのクライアントコードはサービスクラスに依存した実装にならざるをえません
サービス A とサービス B を条件分岐で使い分ける場合、制御側のクライアントコードは両サービスの内部実装や利用条件などを知っていないといけないというわけです
ここでDI コンテナにクライアントクラスを生成させ、さらにDI コンテナがサービスクラスを選択しインタフェースにキャストしてクライアントクラスに渡すようにします
こうすることで、実行時に利用されるサービスクラスは DI コンテナからクライアントクラスに注入されるというわけですね
DI コンテナには、こうした依存関係の注入により制御を反転させ、クラス間を疎結合に分解するという効果があります
--
DI コンテナ Unity が Xamarin の救世主となるワケ
- Xamarin 対応 PCL で提供されている Apache 2.0 ライセンスの DI コンテナです
- Xamarin で問題となるプラットフォーム依存コード、データ、分岐を分解しやすくしてくれます
では DI コンテナの Unity がなぜ Xamarin の救世主となりうるのでしょうか
それは、Xamarin のようなクロスプラットフォーム開発では、冗長なプラットフォーム固有コードや共通コード側の分岐処理が多くなりがちだからです
共通クラスに集約すべき・できる処理やデータが各プラットフォームに記述されたり、共通クラスに各プラットフォームに依存する分岐処理が紛れてしまうと開発生産性や保守性、そして単体テストのしやすさが低下してしまいます
こういった問題の解決策として DI コンテナである Unity が非常に有効に働きます
--
Unity の主な機能
- インスタンスの解決:インタフェースやクラスの型、名称などからクラスインスタンスを生成します
- ライフタイム管理 :クラスインスタンスの共有範囲、破棄条件などを設定・制御できます
- コンストラクタ注入:インスタンス化時に利用するコンストラクタを選択したり、渡す引数のインスタンス化方法を設定できます
- プロパティ注入 :インスタンス化時に初期化用にプロパティに設定する値を設定できます
- メソッド呼び出し :インスタンス化時に初期化用に呼び出すメソッドを設定できます
※ 詳しくは MSDN 付録 A - Unity での依存関係注入 などを参照!
クラスインスタンスを外部から管理・制御するための機能は上記のように色々あるのですが、今回はその中の一部をご紹介します
依存関係の登録とインスタンスの解決
次のコードは、依存関係の登録とインスタンスの解決を行うという Unity の典型的な利用コードです
var container = new UnityContainer();
// 依存関係の登録
container.RegisterType<ITextSpeechService, TextSpeechService>(
null, // 同一型で区別される登録名称(省略可能)
new ContainerControlledLifetimeManager(), // インスタンスの生存管理方法(省略可能)
new InjectionConstructor(typeof(ILogger)), // 注入する依存関係設定(省略可能)
);
// インスタンスの手動解決
var service = container.ResolveType<ITextSpeechService>();
このサンプルでは ITextSpeechService というインタフェースを実装した TextSpeechService という文字列読み上げサービスクラスの依存関係を登録し、手動でインスタンス化しています
インスタンスの生存管理方法として ContainerControlledLifetimeManager を指定することでシングルトンとしてインスタンスを管理する設定を行っています
※ デフォルトではインスタンス解決のたびにインスタンスを毎回生成します
またコンストラクタには ILogger の型を引数1つのみを持つものを選択し、Unity 内の登録状況に従い ILogger 型のインスタンスを自動解決して引数に渡されます
ITextSpeechService のサービスを利用する場合には ResolveType メソッドでインスタンスを解決して利用すれば OK です
Xamarin には DependencyService という DI コンテナ機能がありますが、ここまで柔軟な依存関係の注入はできません!
依存関係の登録を各プラットフォームのプロジェクトの起動処理部分に記述して、インスタンスの解決と利用を共通コード側に記述すればプラットフォームに応じたデータや処理を分岐できてしまうというわけです・・・しかも共通部分のコードはインタフェース経由で外部にアクセスするので単体テストコードを書くのも簡単です!
1日分の記事であまり長文を書くのもあれなので、あとは Xamarin で Unity を活用する場合の参考情報やサンプルコードをご紹介して終わりにします!
--
参考情報
Unity のインスタンス解決を活用して Xamarin で単体テストコードを書いてみたサンプル
https://github.com/matatabi-ux/XamarinUnityResolution
Unity の依存関係注入を活用して Xamarin で配色をプラットフォームごとに切り替えるサンプル
https://github.com/matatabi-ux/XamarinUnityInjection
※ Xamarin × XAML × MVVM ほぼ共通コードで作ってます!
Microsoft patterns & practices - Unity プロジェクトページ
https://unity.codeplex.com/
Unity 3 MSDN(英語)
http://msdn.microsoft.com/ja-jp/library/dn170416.aspx
@IT – 新しいオブジェクト生成機構で EntLib はこう変わる!
http://www.atmarkit.co.jp/fdotnet/entlib/entlibv4/entlibv4_02.html
Xamarin Advent Calendar 2014 次回の記事の投稿者は usamik26 さんです!よろしくお願いしますー!