次の方法で共有


マルチターゲット

デスクトップ、Prism、および Windows Phone 7 を対象にマルチターゲット アプリケーションを構築する

Bill Kratochvil

マイクロソフトは、スケーラビリティが高く拡張可能なアプリケーションを開発するために優れたフレームワークを提供しており、最近のプロジェクトの中には、Prism、Managed Extensibility Framework (MEF)、Unity などのように、マルチターゲット (複数バージョン対応) の機能を提供するものもあります。マルチターゲットは、デスクトップ、Silverlight、および Windows Phone 7 の各プラットフォームで "単一" のコード ベースを共有できるようにします。こうした無償ツールには、クイック スタート、ラボ、および手始めに使用できるたくさんのサンプル コードを含む包括的なドキュメントがあります。投資利益率 (ROI) を最大限に高めるのには、"新しい考え方" でこのようなツールやドキュメントに取り組まなければならないことを理解する必要があります。今回の場合の ROI は、調査や学習に 1 人が費やす時間と考えます。

Prism、MEF、および Unity には、ソフトウェア開発の高度なパターンが使用されているため、大半の開発者にとっては学習が困難です。あまりにも困難なため、ROI が低下するように思えます。これらのプロジェクトでは、新しい考え方が必要になるだけでなく、使用するツールやパターンについての理解も求められます。どこかで理解が不足すると、学習やアプリケーションの安定性の面でコストがかかることになります。さいわい、いくつか基本的概念を身に付ければ、ツールやドキュメントが理解できるようになるだけでなく、Prism、MEF、または Unity のアプリケーション開発に着手し、こうしたプラットフォームを簡単に操作して、マルチターゲット アプリケーションの作成に利用できる最適なものを学習または再利用することができます。ここで身に付けておきたい基本的概念とは、プロジェクト リンカー、依存関係の挿入 (DI)、コードの共有、およびアーキテクチャ パターンです。

プロジェクト リンカー

プロジェクトを複数のプラットフォームで共有することはできません。これを理解しておくことは重要です。デスクトップ プロジェクトから Silverlight プロジェクトを参照することはできません。その逆もまたしかりです。同様に、Windows Phone 7 プロジェクトから Silverlight プロジェクトやデスクトップ プロジェクトを参照することもできません。プロジェクトを共有できないため、コードを共有することになります。このためには、プラットフォームごとに 1 つプロジェクトを作成し、ファイルを "リンク" する必要があります。

Visual Studio のリンク ファイルは、ファイル アイコンのショートカット シンボルで表され、ハード ドライブ上には物理的に存在しません。

図 1 では、Phone (ソース) プロジェクトにのみコードが存在します。Desktop ターゲット プロジェクトと Silverlight ターゲット プロジェクトにはリンク ファイルが含まれ、フォルダーは空です。

Only Source Projects Have Code

図 1 ソース プロジェクトにのみコードが存在する

Prism プロジェクト (compositewpf.codeplex.com、英語) には、プロジェクト リンカー アプリケーションが用意されています。このツールがなければ、マルチターゲット アプリケーションの管理はすぐに困難な作業になるでしょう。このツールを使用してソース プロジェクトを構築して、ターゲット プロジェクトにリンクすれば、ソース プロジェクトで実行する操作 (フォルダーやファイルの追加、名前の変更、削除など) がターゲット プロジェクトでも同時に実行されるようになります。

マルチターゲット アプリケーションでは、名前付け規則がますます重要になります。リンク プロジェクトでは、プラットフォームを表すサフィックス以外は同じ名前をすべて共有します。フォルダー構造を作成する場合は、サフィックスを付けたプロジェクト (Gwn.Infrastucture.Desktop など) を作成してから、プロジェクト構成の既定の名前空間からサフィックスを削除することをお勧めします (図 2 参照)。

Remove the Suffix from the Default Namespace After Creating the Project

図 2 プロジェクト作成後に既定の名前空間からサフィックスを削除する

これで、フォルダー構造があいまいにならなくなり、他のプラットフォームに (同じ名前の) 新しいプロジェクトを作成するときに問題が発生しないようになります。既定の名前空間からサフィックスを削除するのは重要な手順です。複数のプラットフォームでコードを共有するため、コードではプラットフォーム固有の名前空間を使用すべきではありません。使用すると、他のプラットフォームでのコンパイル時に問題が発生することになります。

以上のガイドラインは、開発を円滑に進めるうえでも役に立ちます。(図 2 の Desktop アプリケーションから Silverlight アセンブリを参照するなど) 異なるプラットフォームに不適切なアセンブリ参照を追加すると、(同じアセンブリがどちらの名前空間内にも存在するため) 紛らわしいエラー メッセージが表示されます。プラットフォーム名をサフィックスとして付けておけば、プロジェクト参照をひと目見ただけで問題の原因が明らかになります。

マイクロソフトは、プロジェクト リンカーに関する優れたドキュメント (msdn.microsoft.com/library/dd458870、英語) を提供しています。また、Bing の検索エンジンを使用して "プロジェクト リンカー" を検索すると、BillKrat という私自身のサイトのリンク (プロジェクトをリンクする手順について説明する Web キャストを提供しています) など、役立つリソースを他にも確認できます (注: Visual Studio 2010 を使用している場合、インストール プロセスは、ドキュメントに記載されているプロセスに比べてはるかに簡単になります。[ツール] メニューの [拡張機能マネージャー] をクリックし、"プロジェクト リンカー" を検索してインストールします)。

依存関係の挿入 (DI: Dependency Injection)

Prism、MEF、および Unity について理解するには、DI の理解が必要です。DI を理解しておかなければ、ドキュメントやサンプルは見慣れないもののように感じられ、習得が必要以上に難しくなります。DI については Unity コンテナー (unity.codeplex.com、英語) に限定して説明しますが、DI を理解したら、MEF (mef.codeplex.com、英語) の理解も深まります。

DI コンテナーとは: 大まかに言うと、DI コンテナーとは、クラスを作成する能力のある、見せかけのディクショナリ クラスと見なすことができます。このディクショナリでは、dictionary.add(IFoo,Foo) のようにして、インターフェイスとその実装 (インスタンス) を登録できます。コンテナーに IFoo (インターフェイス) を作成するように指示すると、コンテナーがディクショナリを検索し、型 (Foo) が含まれるのを見つけたら、そのインスタンスを作成します。Foo のインスタンスを作成したら、解決する必要があるインターフェイスが Foo に存在するかどうかを調べます。この一連の流れは、子がすべて正常に作成されるまで、再帰的に続けられます。完了したら、コンテナーは Foo のインスタンスを返します。

コンストラクターとセッターの挿入: 通常、コード ステートメントでは、リソースを使用できるようにクラスのインスタンスを作成します (図 3 の 18 行目)。

Constructor and Setter Injection

図 3 コンストラクターおよびセッターの挿入

DI では、クラスは外部で解決 (インスタンスが作成) され、インスタンスが DI コンテナーによってクラスに挿入されます。Unity では、コンストラクターの挿入およびセッターの挿入の 2 つの挿入をサポートします。コンストラクターの挿入 (図 3 の 25 行目) では、コンテナーが MyTaskConstructorInjection クラスを動的に作成し、IFoo を解決して、コンストラクター パラメーターとして渡します。Unity コンテナーがクラスを構築してパラメーターを挿入したら、Dependency 属性を検索して (図 3 の 33 行目)、プロパティを解決します。コンストラクターの挿入が行われるまで、セッターの挿入は行われないため、コンストラクターの Dependency 属性ではプロパティを参照できません。

型の登録: コンテナーがインターフェイス型 (IFoo など) を解決するには、まず、コンテナーに実装を登録する必要があります (図 4 の 49 ~ 50 行目)。

Registering the Implementation with the Container

図 4 コンテナーに実装を登録する

通常、登録は、初期化クラスになることが多い、アプリケーションのブートストラップ、モジュール、またはプレゼンター/コントローラーで行います。インターフェイスを登録すると、コンテナーは、インターフェイスが依存関係チェーンで見つかったときに、その解決方法を認識します。

拡張可能でスケーラビリティの高いアプリケーション: 説明のために、Foo クラスは、企業が SQL Server データベースにアクセスするために使用するデータ アクセス層 (DAL) だとします。Foo クラスは、何百ものモジュールやたくさんのアプリケーションで使用されます。経営陣が、クラウド サービスについて、マイクロソフトとライセンス契約を交わしたとします。その結果、クラウドを利用するため、アプリケーションをアップグレードしなければなりません。移行の間、Foo クラスは一部のアプリケーションで (SQL Server データベースにアクセスするために) 引き続き使用されますが、Foo クラス以外はクラウドに移行されます。アプリケーションをクラウドに移行する場合、なんらかの理由でデータ移行にエラーが発生する場合に備えて、古いデータベースにすぐに切り替えられるようにしておくことが必要です。以上の処理には、どれくらいのコードが必要でしょう。

DI を使用すると、数行のコードで実行できます。擬似コードは次のようになります。

var  isCloud =  GetCloudConfigurationFromConfigFile();
if(isCloud)
  container.RegisterType<IFoo, FooCloud>();
else
  container.RegisterType<IFoo, Foo>();

エンタープライズ アプリケーションでは統合テストが行われるため、新しい FooCloud DAL ではテスト駆動開発 (TDD) を行うことができます。TDD が完了したら、先ほどのコードを使用して各アプリケーションのブートストラップを更新し、ブートストラップを配置できます。その際、コードを変更していないため、SQL Server データベース (Foo クラス) を引き続き使用するアプリケーションに回帰テストは "必要ありません"。

以下に示すビジネス ロジック層 (BLL) は、何百ものプレゼンターやコントローラーから使用される可能性があります。このビジネス ロジック層ではドメイン オブジェクトを厳密に処理しているため、コードに手を加える必要はありません。つまり、DAL インターフェイス (IFoo) に対してコードを作成するため、BLL を使用するすべてのコードを変更する必要はありません。

public class FinancialDataBll  : IFinancialDataBll
   {
     [Dependency]
       public  IFoo Dal {get;set;}

       public  IEnumerable<FinancialEntity> 
         GetFinanicalData(object sender, EventArgs e)
       {
         // Validate event arguments prior to calling data layer
         var returnResults = Dal.GetFinancialData(sender,e);
         // Handle errors with friendly messages as applicable
         return returnResults;
       }
   }

図 3 の 18 行目で示すように、コードを Foo クラスに密接に結び付けると、アプリケーションの拡張性が低下し、移行プロセスにはコーディングやテストの面で非常にコストがかかることになります。

: DI を効果的に使用するには、BLL と DAL を適切な構造にする必要があります。BLL には、接続文字列、SQL ステートメント、XML ファイルとしてのファイル ハンドルなど、DAL コンポーネントの情報が存在しないようにします。同様に、プレゼンテーション層 (UI コンポーネント) にも DAL の情報は存在せず、BLL のみ認識するようにします (注: プレゼンテーション層で DI を使用して BLL を解決していれば、BLL は DAL と同じように簡単に入れ替えることができます。これは、リファクタリングを行う必要があっても、1 つのアプリケーションしかリファクタリングの影響を受けないようにする場合に非常に役に立ちます)。

イベント アグリゲーション: 結び付きのないコンポーネント間で通信を行うには課題が伴います。たとえば、図 5 のオブジェクト D には、ユーザーが通貨の種類を米ドルからユーロなどに換算する際に使用するドロップダウン リストが含まれるとします。

Communication Between Decoupled Objects

図 5 結び付きのないオブジェクト間の通信

オブジェクト B と F には、現在選択している通貨が適用されているため、通貨を変更する際は再計算が必要です。1 つの解決策は、イベントを A にバブルアップする方法です。これにより、A から B を、B から C を、C から D をサブスクライブします。次にA から E に情報をトンネルし、続いて E から F にトンネルします。アプリケーションのサイズが大きくなると、このプロセスはより複雑になります。この複雑さはテストにも影響し、パス内に条件ステートメントを追加すると、影響を受けるすべての領域で回帰テストを行わなければなりません。

この解決策でメモリ リークを回避するには、影響を受けるすべてのオブジェクトに IDisposable インターフェイスを実装し、そこですべてのイベント サブスクリプションを破棄する必要があります。ただし、これにより、管理すべき複雑さが増し、他の層にも及びます。

Prism: イベント アグリゲーションは、Prism が威力を発揮する多くの領域の 1 つです。Prism では、次のような構文を使用して、オブジェクト D にイベントを簡単に発行できます。

aggregator.GetEvent<MyEvent>().Publish(MyPayload)...

オブジェクト B と F では、このイベントをサブスクライブすることになりますが、コードを数行作成するだけです。あとは、ビジネス ロジックに重点を置き、インフラストラクチャに関する作業に時間をかける必要はありません。オブジェクト B と F によるサブスクライブのコード例を以下に示します。

[Dependency]
public ILoggerFacade Logger {get;set;}

private  IEventAggregator _eventAggregator;
[Dependency]
public  IEventAggregator EventAggregator 
{
  get { return _eventAggregator; }
  set { 
    _eventAggregator=value;
    OnEventAggregatorSet();  // Subscribe to events in this method
  }
}

もう 1 つ例を示します。

public  MyConstructor(IEventAggregator aggregator){
  aggregator.GetEvent<MyEvent>().Subscribe(HandleMyEvent);  
}
public void HandleMyEvent(MyEventArgs e){
  Logger.Log("HandleMyEvent is handling event in Foo", Category.Debug, Priority.None);
 // Do something useful
}

コードと XAML を共有する

電子医療記録 (EHR: Electronic Health Record) の認定要件が確立される前 (これにより、小さなオフィスでは、EHR 開発に桁違いのコストがかかるようになりました)、小規模医療グループを対象にした EHR アプリケーションを作成しました。まず、患者の治療内容と請求額を正確に管理するため、Windows Mobile PDA と Web サイトを使用しました。PDA にはすべてのビジネス ロジックを含め、Web サイトには請求に携わるスタッフ向けのインターフェイスを用意しました。PDA の機能を徐々に Web サイトに移行し、すべてのビジネス ルールと動作も移行することを想定していました。ところが、厄介なことに、後からタブレットとラップトップ用にデスクトップ アプリケーションを作成するように依頼されました。つまり、1 年以内に、プロジェクトの範囲が PDA から 3 つのすべてのプラットフォームに広がりました。ここでは、3 つのコード ベースを個別に管理する必要があります。しかし、各コード ベースには、プラットフォーム固有のバリエーションがあるため、ビジネス ロジックを簡単には共有できません。

Prism プロジェクトにプロジェクト リンカーが登場し、patterns & practices 設計チームが、プラットフォーム間で同じ名前空間を使用して、マルチターゲット環境をサポートするように方向転換すると、この流れに伴って生じる波及効果を十分に理解したためすぐに便乗しました。マルチターゲットを使用すると、非常に短時間かつクライアントのコストを最小限に抑えて、EHR プロジェクトの開発、アップグレード、およびメンテナンスを行うことができます。

コード: サポートの対象とするプラットフォームについては熟慮する必要があります。サポートの必要性が最も少ないプラットフォームで、単一のコードベースを使用することが重要です。たとえば、Silverlight 環境とデスクトップ環境のみをターゲットにプログラミングする場合は、Silverlight プロジェクトをソース プロジェクトに設定し、デスクトップ プロジェクトをリンクします。Windows Phone 7、Silverlight、およびデスクトップをサポートのターゲットにする場合は、Windows Phone 7 プロジェクトをソース プロジェクトにする必要があります。

他のプラットフォームではコンパイルしないコードを作成して時間を無駄にしたくないため、このことは重要です。たとえば、Windows Phone 7 プラットフォームで開発すれば、IntelliSense を利用して、フレームワークの使用可能な機能をすぐに確認できます。他のプラットフォームでもコンパイルされるという確信を持ってコードを作成できます。

また、プロジェクトの "条件付きコンパイル シンボル" の構成に標準を設定することをお勧めします (図 6 で強調表示した部分が既定の設定です)。

Set Compiler Symbols for Each Platform

図 6 各プラットフォームにコンパイル シンボルを設定する

"SILVERLIGHT" が Windows Phone 7 プロジェクトと Silverlight プロジェクトの両方で共有されるため、これでは問題が発生します。Silverlight 4 固有のコードを作成するには、次のコードが必要です。

#if SILVERLIGHT
#if !WINDOWS_PHONE
  // My Silverlight 4-specific code here 
#endif
#endif

XAML: XAML は、特に Silverlight とデスクトップ アプリケーションの間で、驚くほど簡単に再利用できます。これは、XAML にアセンブリ参照を含めないようにするとうまくいきます。つまり、外部アセンブリにある実際のクラスをサブクラス化するローカル プロジェクト内に、ラッパー クラスを作成するとこれを実現できます (図 7 の左上のパネル参照)。

Create a Wrapper Class for the Current Project

図 7 現在のプロジェクトにラッパー クラスを作成する

UserControlBase クラスで、プラットフォーム固有のリソース ファイルをプログラムで読み込んでいることに注目してください。このリソース ファイルには、ファイルの共有に影響を与える可能性がある XAML 宣言を最小限に抑えることができる、コンバーター、スタイル、およびテンプレートを保持します。

アーキテクチャ パターン

部屋に 10 人のプログラマを集めて、同じ開発タスクを割り当てると、そのタスクを正常に完了する方法が 10 とおりになる可能性があります。開発者であれば、さまざまなレベルのアーキテクチャやコーディングに関する経験を重ねることで、その経験が作成するコードに反映されます (そのため、エンタープライズ アプリケーションを把握や管理が困難になります)。アーキテクチャ パターンやアーキテクチャ標準は、経験から共通の核を提供するため、10 人の開発者は同様のコードを作成して部屋を出てくることになります。

Windows Presentation Foundation (WPF)、Prism、MEF、および Unity では、それぞれ独自の開発環境を導入します。マルチターゲットを追加すると、複雑さのレベルが増します。、プラットフォーム固有のコードを最小限に抑え、マルチターゲットに効果的に対応しているほど、顕著に複雑さが増します。アジャイル環境では、テクノロジが進化するにつれて、新たなテクノロジを効果的に活用できるように、パターンを絶えず更新する必要があります。そのため、このような強力なツールが提供するサンプルを確認する場合は、必然的に、たくさんのパターンの組み合わせを調べることになります。

パターンを把握していなければ、ツール、ドキュメント、およびサンプルを理解するのは困難です。さらに悪いことに、意図した設計に反する方法で、このような強力なツールを使用する可能性があります。これは、プロジェクトを成功に導くうえでリスクをもたらすことになります。Prism ドキュメントの付録 B では、使用できるパターンについての包括的な情報が提供されています。ここからは、プレゼンテーション パターンの進化についてまとめます。

モデル - ビュー - コントローラー (MVC: Model-View-Controller) アプリケーション モデル: このモデルは、MVC で発生した問題の解決策として登場しました。具体的な問題点とは、ビジネス ロジックと UI 状態 (テキスト色、リストでの選択された項目、コントロールの可視性など) によるドメイン オブジェクトの汚染です。このモデルでは、(MVC では許可されていない) ビューを直接更新する機能も提供します。

アプリケーション モデルは、ビューとモデルの間に挿入され、動作、状態、モデルとの同期を管理するためのビジネス ロジックを含みます。ビューはアプリケーション モデル (モデルではありません) にバインドされます。

MVC プレゼンテーション モデル: プレゼンテーション モデルとアプリケーション モデルの主な違いは、ビューを更新する機能にあります。プレゼンテーション モデルは MVC ガイドラインに従って、ビューの直接更新を許可しません。

モデル - ビュー - ビューモデル (MVVM: Model-View-ViewModel): MVVM 作成者の John Gossman は次のように述べています。

「名前を付ける時点で、MVVM パターンは、WPF 固有のバージョンのプレゼンテーション モデル パターンだと考えていました。プレゼンテーション モデルは、非常に簡単に説明および作成でき、広く知られているモデルですが、ここでは、WPF らしさを保持し、解釈の不一致を避けるために、私個人の考えで MVVM という用語にこだわります。」

モデル - ビュー - プレゼンター (MVP: Model-View-Presenter): MVP は、MVC、アプリケーション モデル、およびプレゼンテーション モデルの各パターンに限定した解決策でした。MVP では、開発者にビューとビューモデルを制御する機能が与えられます。Windows 開発者は、常に、優れたコントロールを使用できていたため、多くの開発者が MVC と MVP の違いを明確に理解していない可能性があります。少し調査すると、OS やコントロールにはコントローラーの大半の機能が含まれるため、Windows の登場によって MVC コントローラーは時代遅れなものとなったことがわかります。

MVC から進化する必要があったのは、時代遅れなコントローラーだけではありませんでした。既に説明したように、アプリケーション モデルやプレゼンテーション モデルでは、他の要素についても制限がありました。

MVP のコンポーネントの概要を次に示します。

モデル: モデルは、ビューにバインドするデータを保持します。

ビュー: ビューは、データ バインドを通じてモデルのコンテンツを表示します。ビューは複数のプレゼンターで共有できるため、このような分離が重要になります (注: 2006 年、Martin Fowler によって、MVP パターンは監視コントローラー (Supervising Controller) とパッシブ ビュー (Passive View) の 2 つの明確に異なるパターンに分けられました。両者の主な違いはデータ バインドにあります。データ バインドを使用すると、監視コントローラーと呼ばれます (先ほど説明した役割に従います)。データ バインドを使用しない場合は、パッシブ ビューと呼ばれ、役割が変化します。この MVP パターンは、ビューとモデルの同期を保つプレゼンターの役割のみになります)。

プレゼンター: プレゼンターは、ビューとモデルの両方を認識し、ビジネス ロジックを処理し、モデルを設定する役割があります。

モデル - ビュー - プレゼンター、ビューモデル (MVPVM: Model-View-Presenter, ViewModel): この (名前のない) パターンは、Prism プロジェクトの初期段階に見受けられ、MVP と MVVM の機能を組み合わせたパターンでした。

// Load the view into the MainRegion 
  // after the presenter resolves it
  RegionViewRegistry.RegisterViewWithRegion("MainRegion", () => 
    presenter.View);

patterns & practices チームが、Prism、Unity、Smart Client Software Factory (SCSF)、および Web Client Software Factory (WCSF) プロジェクトを使用して得た教訓を踏まえて、この簡単なコード行を使用すると、MVPVM と呼ぶのにふさわしいパターンを作成できます。プレゼンターでは、このパターンを使用して、ビューモデル、ビュー、および必要な BLL コンポーネントの解決 (インスタンスの作成) を行います。その後、対応する BLL メソッドを必要に応じて呼び出し (図 8 参照)、ビューを表示するためにビューモデルにデータを設定します。

Model-View-Presenter, ViewModel  (MVPVM) and Associated Components

図 8 モデル - ビュー - プレゼンター、ビューモデル (MVPVM: Model-View-Presenter, ViewModel) と関連コンポーネント

ビジネス ロジックはプレゼンターに存在するため、ビューモデルは他のプレゼンターでも簡単に再利用できます。また、特に、コントロール参照が必要なときに、プレゼンターからビューを直接更新して、(必要に応じて) 複雑なバインド ロジックを取り除くことができます。このようにして、MVPVM では、(著名な設計者が述べたように) マルチターゲットの Prism および DI 環境向けに、アプリケーション モデル、プレゼンテーション モデル、および MVVM の制限事項をすべて解決します。

先ほどのコード行は、PasswordMgr.CodePlex.com (英語) にある Password Manager オープン ソース プロジェクトの SecurityModule モジュールで確認できます。このマルチターゲット プロジェクトには、"単一のコード ベースを共有する" デスクトップ アプリケーション、Silverlight アプリケーション、および Windows Phone 7 アプリケーションと、"同じ XAML を共有する" Silverlight アプリケーションおよびデスクトップ アプリケーションが含まれています。

(注: この記事を執筆している時点では、Windows Phone 7 プラットフォームに DI コンテナーの公式サポートはありません。このプロジェクトについては、Windows Mobile 6.5 プロジェクト (mobile.codeplex.com、英語) からコンテナー モデルをダウンロードし、Unity プロジェクト (unity.codeplex.com、英語) から IUnityContainer インターフェイスを実装して、たくさんの Unity 単体テストを使用し、すべての単体テストに合格するまで TDD を実行しました。外観と操作性が Unity に似ている、新しく構築した DI コンテナーを使用すると、Prism プロジェクトを移植できました。この Password Manager プロジェクトには、800 個以上の単体テストが用意されていますが、コンパイルを実行した結果、エラー、警告、およびメッセージは生成されません)。

モデル: DAL には、保存済みのモデル オブジェクトに関する役割のみがあります。また、保存済みモデル オブジェクトをドメイン オブジェクト (すべてのエンタープライズ アプリケーション層の範囲内にあるモデルを表すエンティティ) に転送する役割もあります (注: BLL はプレゼンテーション層やモデルを認識しません。インターフェイスを通じて、DAL と通信するだけです)。

ビュー: ビューは、ビューモデル (データ バインド) を監視して、必要に応じてビューモデルのデータを表示します。ビューはビューモデルを 1 つしか使用できませんが、ビューモデルは複数のビューから共有できます。

プレゼンター: プレゼンターは、ビューとビューモデルのインスタンスの作成、ビューのデータ コンテキストの設定、イベントの定義、イベントや動作 (マウスやボタンのクリック、メニューの選択など) のビジネス ロジックの処理を担当します。

プレゼンターは、(共有) BLL を使用して、ビジネス ロジックを処理し、保存済みのモデル データで作成、読み取り、更新、削除 (CRUD) の操作を実行します (注: BLL は単体テストが容易で、DI を使用して簡単に置き換えることができます)。

プレゼンターは、ビュー、ビューのコントロール、およびビューモデルを直接変更する MVP の機能を共有します。

ビューモデル: ビューモデルは、たくさんのビューで再利用できるため、常に共有を念頭に置いて設計します。

ビューモデルは、イベント アグリゲーション (推奨) またはインターフェイス (汎用機能向け) のいずれかを使用して、プレゼンターと通信できます。通常、これは、(プレゼンター基本クラスと通信する) ビューモデル基本クラスで処理されます。プレゼンターはすべてのビジネス ロジックを処理しますが、ビューがコマンドとイベントをビューモデルにバインドするため、この通信が必要になります。このようなイベントは、疎結合の処理方法でプレゼンターに伝達する必要があります。

能力と多用性

このような基本概念を身に付ければ、図 9 に示すようなコード セグメントを見慣れないと感じることはなくなるでしょう。

Module Registrations

図 9 モジュールの登録

patterns & practices チームが提供するツールの能力と多用性は明らかで、大きな ROI が見込まれます。このようなツールにより、インフラストラクチャの複雑さが軽減され、疎結合で拡張可能な、スケーラビリティが高いアプリケーションを作成できます。このようなアプリケーションは、信頼性が高く安定した方法を使用して、より少ないリソースで多くの処理を行うことができるように、同じコード ベースを共有できます。

層 (プレゼンテーション層、BLL、および DAL) を効果的に使用すると、懸案事項が明確に分離され、複数のモジュールやアプリケーションでコンポーネントを再利用できるようになります。これにより、テスト、新規開発、アップグレート、およびメンテナンスにかかるコストが最小限に抑えられます。

最も重要なことは、経験と専門知識を活かして、絶えず変化する環境を切り抜けることができ、対応が非常に迅速でアジャイルなチームを作成できることです。これで、単一のコード ベースで (インフラストラクチャではなく) ビジネス ロジックの機能の開発に専念でき、Windows Phone 7、Web、タブレット、デスクトップの各プラットフォームで機能するアプリケーションを構築できます。

Bill Kratochvil は、フリーの契約社員であり、医療業界の大手企業の機密プロジェクトに携わる、選り抜きの開発者チームの第一線に立つ技術者兼設計者です。彼自身は、テキサス州のアマリロに拠点を置く Global Webnet LLC に勤務しています。

この記事のレビューに協力してくれた技術スタッフの Christina HeltonDavid Kean に心より感謝いたします。