ホーム > Silverlight > MVVMでのServiceLocatorの導入

MVVMでのServiceLocatorの導入


MVVM Lighttoolkit では、ViewModelはServiceLocatorが提供する仕組みになっています。いや、別にこれまでのエントリーのように、ServiceLocatorを使わなくても構築できるんですけれど、そうなっているからには何かしらの理由が有るはずです。。今回は、ServiceLocatorって何者よっていうのを解説してみようと思います。

ServiceLocatorとは

ServiceLocatorとは、プログラマーの代わりにクラスのインスタンスを管理してくれる子です。

通常クラスの実体が欲しければ、newキーワードでインスタンス化するわけですが、ServiceLocatorにクラスのインスタンスを管理してもらうことで、クラスの生成時に処理を割りこませたり、インスタンスを差し替えたりできるので、MVVMなどのレイヤー型のアーキテクチャーを採用しているプロジェクトとはそれなりに相性が良いです。これがもう少し進むとIoCが出てくるんですが、まぁそこまで行かなくてもいいでしょう。

インスタンスの差し替えと生成の割り込み

MVVMに限らないのですが、内部に持っているサービスクラスを差し替えたいことがあります。

例えば、作ったモジュールの単体テストをしたいんだけれど、依存している部分のせいでテストが行えなかったり、外部のWebサービスを参照していたり、参照するクラスライブラリがまだ実装していたりしない場合などです。このような場合、サービスの振る舞いをインターフェイスに抽象化して、サービスをテスト用のものに差し替えると、このような問題を回避できます。

具体的にはこんな感じです。

    public class SampleViewModel: ViewModelBase
    {
        public IHelloService service { get; set; }

        public SampleViewModel()
        {
        }

        public string GetHelloMessage()
        {
            return service.GetMessage();
        }
    }

    public class SampleServiceLocator
    {
        public SampleViewModel Sample
        {
            get {
                return new SampleViewModel
                {
                    service = new HelloService(),
                };
            }
        }
    }

この場合、HelloServiceはIHelloServiceとして抽象化されているので、例えばテスト時にはこんなクラスに差し替えてSampleViewModelのテストをすることができます。また、XAMLでクラスのインスタンスを作成する場合、引数なしコンストラクターが呼び出されるのですが、ServiceLocator側でプロパティーとして公開し、内部で引数付きのコンストラクターを呼び出すことも可能です。

単体テストが嬉しい

SampleViewModelの単体テストをしたいけれど、HelloServiceがまだ出来ていないとか、Webサービスを参照しているとか行った場合、HelloServiceの都合で、SampleViewModelがテストできないなんてことになります。ただ、サービスをインターフェイスに切りだしてあれば、単体テスト時にモック用のサービスに差し替えることでこんなふうにテストできますよね。

    [TestClass]
    public class Tests
    {
        [TestMethod]
        public void TestMethod1()
        {
            var target = new SampleViewModel();
            target.service = new HelloServiceMock();
            var actual = target.GetHelloMessage();
            Assert.AreEqual<string>("てすと", actual);
        }
    }
デザイン時に嬉しい

Silverlightでは、Blendなどで画面を編集する場合はコンストラクターでWebServiceからデータの取得などを行っているとデザイン画面が開けない。なんてことが起きるので、通常はViewModel内部で実行時の動作なのか、デザイン時の動作などかを判断し、コードを振り分けるなんてことをします。

この場合も、デザイン用のサービスをViewModelに与えることで、ViewModel内に実行時かどうかの判断を各必要がなくなります。たとえば、さっきのGetHelloMessageメソッド内部で判断しようとするとこうなるけれど、

        public string GetHelloMessage()
        {
            if (DesignerProperties.IsInDesignTool)
            {
                return "でざいんようめっせーじ";
            }
            else
            {
                service.GetMessage();
            }
        }

これよりは、デザイン用のサービスを用意して、生成時に差し替えて、GetHelloMessageメソッド自体では単に与えられたサービスを呼び出すほうが、ifの分岐がなくなる分嬉しいですよね。

    public class SampleServiceLocator
    {
        public SampleViewModel Sample
        {
            get {
                return new SampleViewModel
                {
                    service = (DesignerProperties.IsInDesignTool) 
                                    ? new DesingHelloService()
                                    : new HelloService(),
                };
            }
        }
    }
まとめ

MVVM Lighttoolkitでは、プロジェクトテンプレートで、MVVMのプロジェクトを作ると、ServiceLocatorをApp.xamlでインスタンス化し、各XAMLページでは、このLocatorが持っている各ViewModelをバインドすることでViewModelをViewに関連付けています。

ということで、ServiceLocatorを導入することで、クラスの生成に割り込めるので、テストがしやすくなったり、ブレンドでのデザインがしやすくなるというのを確認してもらえたのではないかと思います。

広告
カテゴリー:Silverlight タグ: ,
  1. まだコメントはありません。
  1. No trackbacks yet.

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。