印刷用ページ       送信     
クリックして評価とフィードバックをお寄せください
MSDN
MSDN ライブラリ
テクニカルドキュメント
その他ドキュメント
Patterns & Practices
 モデル ビュー コントローラ
モデル ビュー コントローラ

Microsoft Corporation

June 2003

日本語版最終更新日 2004 年 4 月 21 日

コンテキスト

コンピュータ システムの多くは、データ ストアからデータを取得し、ユーザーに対して表示することを目的としています。ユーザーがこのデータを変更すると、システムによって更新内容がデータ ストアに保存されます。情報は主にデータ ストアとユーザー インターフェイスとの間を流れるため、両者を 1 つに結合すれば、コーディングの量を減らし、アプリケーションのパフォーマンスを向上できるのではないかと考えがちです。ところが、これは自然なアプローチのように見えますが、重要な問題を含んでいます。まず、ユーザー インターフェイスはデータ ストレージ システムよりもかなり頻繁に変化する傾向にあります。また、ビジネス アプリケーションには通常、データ転送機能を超えるビジネス ロジックが組み込まれていることも、データ要素とユーザー インターフェイス要素との結合を難しくしています。

問題

Web アプリケーションのユーザー インターフェイス機能をモジュール化して、個々の要素を簡単に変更できるようにするにはどうすればよいでしょうか。

影響

この状況のシステムでは以下の影響が及んでいるため、問題の解決を考える場合にこれらの影響を調整する必要があります。

  • ユーザー インターフェイスのロジックは、ビジネス ロジックよりも頻繁に変化する傾向があります。これは特に、Web ベースのアプリケーションで顕著です。たとえば、新しいユーザー インターフェイス ページが追加されたり、既存ページのレイアウトが大幅に変更されたりする場合があります。ただし、アプリケーションを再配布する必要なくいつでもユーザー インターフェイスを変更できるというのは、Web ベースのシンクライアント アプリケーションの長所の 1 つです。プレゼンテーション コードとビジネス ロジックを 1 つのオブジェクトに結合した場合、ユーザー インターフェイスを変更するたびに、ビジネス ロジックを含むオブジェクトを変更する必要があります。これによってエラーが生じる可能性があるため、ユーザー インターフェイスを少しでも変更した場合は、すべてのビジネス ロジックの再テストが必要です。

  • アプリケーションで同じデータを異なる形式で表示する場合があります。たとえば、ある分析者はデータをスプレッドシートで表示したいと思い、管理者側は同じデータを円グラフで確認したい場合があります。一部のリッチクライアント ユーザー インターフェイスでは、同じデータが一度にさまざまな形式で表示されます。ユーザーがあるビューでデータを変更した場合、システムはこのデータを使っている他のすべてのビューを自動的に更新する必要があります。

  • 視覚的な魅力と効率性を兼ね備えた HTML ページを設計するには通常、複雑なビジネス ロジックの開発とは異なるスキルが必要です。これらのスキルを両方とも持っている人はまれです。したがって、この 2 つの部分は別々に開発することが望ましいといえます。

  • 通常、ユーザー インターフェイスのアクティビティはプレゼンテーションと更新の 2 つに分けられます。プレゼンテーションのアクティビティでは、データ ソースからデータを取得し、取得したデータをフォーマットして表示します。ユーザーがデータに基づくアクションを実行すると、更新のアクティビティでコントロールがビジネス ロジックに戻され、データが更新されます。

  • Web アプリケーションでは、1 つのページ要求によって、ユーザーが選択したリンクに関連付けられているアクションの処理とターゲット ページのレンダリングが組み合わされます。多くの場合、このターゲット ページとアクションは直接関係していません。たとえば、項目のリストを表示するだけの簡単な Web アプリケーションを考えてみます。ユーザーは、項目をリストに追加、またはリストから削除してから、リストのメイン ページに戻ります。したがって、アプリケーションでは、1 つの HTTP 要求で 2 つのまったく異なるコマンド (追加や削除) を実行してから、同じページ (リスト) をレンダリングする必要があります。

  • ユーザー インターフェイスのコードはビジネス ロジックよりもデバイスに依存する傾向にあります。ブラウザベースのアプリケーションから、携帯情報端末 (PDA) や Web 使用可能な携帯電話をサポートするアプリケーションに移行する場合、ユーザー インターフェイスのコードは大きく変更する必要がありますが、ビジネス ロジックは変更しなくてもよい場合があります。この 2 つの部分をはっきりと分離することにより、移行がしやすくなり、ビジネス ロジックにエラーが入り込むリスクが最小限に抑えられます。

  • ユーザー インターフェイス用の自動テストの作成は、一般に、ビジネス ロジック用自動テストの作成よりも難しく、時間がかかります。したがって、ユーザー インターフェイスに直接関係するコードの量を減らすことにより、アプリケーションがテストしやすくなります。

解決策

モデル ビュー コントローラ (MVC: Model-View-Controller) パターンでは、ユーザーからの入力に基づいて、ドメインのモデリング、プレゼンテーション、およびアクションを次の 3 つのクラスに分けています [Burbeck92]。

  • モデル - モデルはアプリケーション ドメインの動作とデータを管理し、そのドメインの状態に関する情報の要求 (通常はビューから) や、状態の変更命令 (通常はコントローラから) に応答します。

  • ビュー - ビューは情報の表示を管理します。

  • コントローラ - コントローラはマウスやキーボードを使用するユーザーからの入力を解釈し、必要に応じて、モデルやビューに対し変更を通知します。

    図 1 は、これら 3 つのオブジェクトの構造関係を示しています。

    des_MVC_Fig01.gif


    1. MVC クラスの構造

    ビューとコントローラの両方がモデルに依存していることに注意してください。ただし、モデルはビューとコントローラのどちらにも依存していません。これはクラス分けの重要な長所の 1 つです。このクラス分けにより、視覚的なプレゼンテーションとは別に、モデルを構築し、テストできるようになります。リッチ クライアント アプリケーションの多くではビューとコントローラの区別はあまり重要ではなく、実際、ビューとコントローラを 1 つのオブジェクトとして実装しているユーザー インターフェイス フレームワークは多数あります。一方、Web アプリケーションでは、ビュー (ブラウザ) とコントローラ (HTTP 要求を処理するサーバー側コンポーネント) の区別は厳密に定義されています。

    モデル ビュー コントローラは、ユーザー インターフェイス ロジックをビジネス ロジックから区別するための基本的な設計パターンです。ただし、このパターンは広く採用されているため、結果として、数々の誤った解釈がなされています。特に、"コントローラ" という言葉は使われる状況が異なると、その意味も変わります。幸い、Web アプリケーションの登場によりビューとコントローラの区別が明確になったため、このようなあいまいさは多少解決されています。

バリエーション

『Application Programming in Smalltalk-80: How to use Model-View-Controller (MVC)』 [Burbeck92] で Steve Burbeck は、パッシブ モデルとアクティブ モデルという MVC の 2 つのバリエーションについて説明しています。

パッシブ モデルは、1 つのコントローラでモデルが排他的に操作されるときに使用されます。コントローラはモデルを変更した後、モデルが変更されたため更新する必要があることをビューに通知します (図 2 を参照)。このシナリオでは、モデルはビューとコントローラから完全に独立しています。つまり、モデルには状態の変更を通知する手段がまったくありません。HTTP プロトコルがこの例です。ブラウザにはサーバーからの非同期更新情報を受ける簡単な手段がありません。ブラウザはビューを表示し、ユーザーからの入力に応答しますが、サーバー上のデータの変更は検知しません。ユーザーが明示的に更新を要求した場合のみ、サーバーに対して変更の問い合わせが行われます。

des_MVC_Fig02.gif


2. パッシブ   モデルの動作

アクティブ モデルは、コントローラとは関係なくモデルで状態が変更される場合に使用されます。これは別のソースでデータが変更され、この変更をビューに反映する必要がある場合に起こります。株価相場表示を例に考えてみます。株価データが変更された場合、外部ソースからデータを受け取り、チッカー バンドや警告ウィンドウなどのビューを更新する必要があります。モデルの内部状態の変更が検知できるのはモデルだけなので、モデルからビューに表示を更新するよう通知する必要があります。

ただし、MVC パターンを使用する動機の 1 つが、モデルをビューから独立させるということです。モデルがビューに変更を通知しなければならないとすると、回避しようとした依存性が再度取り入れられることになります。そこで、オブザーバ (Observer) パターン [Gamma95] には、依存性を持たせずに、他のオブジェクトに状態の変更を知らせるメカニズムが用意されています。個々のビューにオブザーバ インターフェイスを実装し、個々のビューをモデルに登録します。モデルでは、変更をサブスクライブするオブザーバすべてのリストが管理されます。モデルが変更されると、モデルによって、登録されているオブザーバすべてに処理が施され、変更が通知されます。このアプローチは一般に、"パブリッシュとサブスクライブ" と呼ばれます。モデルは、いずれのビューの固有情報もまったく必要としません。実際、たとえば、メニュー オプションを有効化または無効化するなど、モデルの変更をコントローラに通知する必要があるシナリオでは、コントローラ側で行わなければならないことは、オブザーバ インターフェイスを実装し、モデルの変更をサブスクライブすることだけです。多数のビューがある状況では、複数のサブジェクトを定義し、それぞれのサブジェクトが 1 つの特定種類のモデル変更を記述するようにします。これによって、各ビューではそのビューに関係する種類の変更だけをサブスクライブすることができます。

図 3 は、オブザーバを使用したアクティブ MVC の構造と、オブザーバによってモデルが直接ビューを参照できないように分離されているようすを示しています。

des_MVC_Fig03.gif


3. オブザーバを使用した、アクティブ   モデルでのビューからのモデルの分離

図 4 は、オブザーバがモデルの変更をビューに通知するようすを示しています。ただし、Unified Modeling Language (UML) シーケンス ダイアグラムは、クラスやインターフェイスではなくオブジェクトのインスタンスを表すため、このダイアグラムを使ってモデルとビューの分離を説明する良い方法はありません。

des_MVC_Fig04.gif


4. アクティブ   モデルの動作

ASP.NET でのモデル ビュー コントローラの実装」を参照してください。

テストに関する考慮事項

モデル ビュー コントローラ (MVC) を使用すると、テスト容易性が大きく強化されます。コンポーネント間の依存性が高いとコンポーネントのテストは難しくなります。これは、特にユーザー インターフェイス コンポーネントの場合に顕著です。この種類のコンポーネントでは通常、単純な機能をテストするだけでも複雑なセットアップが必要になります。さらに、エラーが発生した場合、問題の原因となっているコンポーネントを特定するのが困難です。このような理由により、さまざまな問題を分離することが、アーキテクチャ上で重要になります。MVC では、データの保存、表示、更新の個々の問題が、個別にテスト可能な 3 つのコンポーネントに区分されます。

相互依存性に起因する問題の他、ユーザー インターフェイス フレームワークのテストも本質的に困難を伴います。ユーザー インターフェイスのテストには、単調でエラーを引き起こしやすい手動によるテストか、ユーザー アクションをシミュレートするテスト スクリプトが必要です。このようなスクリプトは開発に時間がかかり、脆弱であるという傾向があります。MVC を使用する場合でもユーザー インターフェイスのテストは必要ですが、プレゼンテーション ロジックからモデルを分離することにより、プレゼンテーションとは関係なくモデルをテストできるため、ユーザー インターフェイスのテスト ケース数を減らすことができます。

結果のコンテキスト

MVC パターンを中心としたプレゼンテーション層の構築には、以下の長所と短所があります。

長所

  • 複数ビューのサポート - ビューはモデルから分離していて、モデルがビューに直接依存していることはないため、ユーザー インターフェイスでは同じデータを同時に複数のビューに表示できます。たとえば、Web アプリケーションの複数ページで、同じモデル オブジェクトを使用できます。また、ユーザーが複数ページの外観を変更できる Web アプリケーションもこの一例です。これらのページには共有モデルからの同一データをページごとに外観を変えて表示できます。

  • 変更への対処 - ユーザー インターフェイスに対する要件は、ビジネス ルールよりも頻繁に変更される傾向にあります。ユーザーによって、好みの色、フォント、画面レイアウト、および携帯電話や PDAなど新しいデバイスに対するサポート レベルが異なる場合があります。モデルはビューに依存していないため、システムに新しい種類のビューを追加しても一般的にはモデルは影響を受けません。結果として、変更の範囲はビューだけにとどまります。このパターンは、ページ コントローラ (Page Controller) やフロント コントローラ (Front Controller) などのさらに特殊化したパターンの基礎となります。

短所

  • 複雑性 - MVC パターンにより、新しいレベルの間接手段が導入されるため、ソリューションが多少複雑になります。また、ユーザー インターフェイス コードのイベント駆動型の性質が強まるため、デバッグがさらに難しくなります。

  • 頻繁な更新に伴うコスト - モデルとビューを分離するからといって、モデルの開発者がビューの性質を無視できるわけではありません。たとえば、モデルが頻繁に変更される場合、大量の更新要求でビューがいっぱいになる可能性があります。グラフィック表示などのビューによっては、レンダリングに時間がかかる場合があります。結果として、ビューは更新要求を処理しきれなくなる可能性があります。そのため、モデルのコーディング時には、ビューを念頭に置くことが重要です。たとえば、モデルでは複数の更新をビューに対する 1 つの通知にまとめることができます。

バリアント

ドキュメントビュー バリアントは、モデル ビュー コントローラの 3 つの役割をすべて認識しますが、コントローラをビューにマージします。ドキュメントは MVC でのモデルの役割に相当します。このバリアントは、多くの既存 GUI プラットフォームに存在します。Microsoft Visual C++® 環境の Microsoft® Foundation Class Library (MFC) はドキュメントビューのよい例です。このバリアントを使用すると、ビューとコントローラがより密接に結合されます。

関連パターン

詳細については、以下の関連パターンを参照してください。

  • オブザーバ (Observer) - ビューとその関連モデルを常に同期させておく必要があるため、このパターンは MVC と共に言及されることがよくあります。

  • ページ コントローラ」 (Page Controller) と「フロント コントローラ」 (Front Controller) では、MVC パターンのコントローラ部分の実装方法について説明しています。

参考

モデル ビュー コントローラは、1970 年代の後半に Smalltalk プラットフォームのためのフレームワークとして、Trygve Reenskaug によって開発されました [Fowler03]。ここでは次の文献を参考に説明しました。

[Burbeck92] 『Application Programming in Smalltalk-80:How to use Model-View-Controller (MVC)』 Steve Burbeck 著(University of Illinois in Urbana-Champaign (UIUC) Smalltalk Archive) - http://st-www.cs.uiuc.edu/users/smarch/st-docs/mvc.html  leave-ms.gif で入手できます。

[Fowler03] 『Patterns of Enterprise Application Architecture』 Martin Fowler 著(Addison-Wesley、2003 年)

[Gamma95] 『Design Patterns:Elements of Reusable Object-Oriented Software』 Gamma、Helm、Johnson、Vlissides 共著(Addison-Wesley、1995 年)

PATTPRAC.gif

© 2009 Microsoft Corporation. All rights reserved. 使用条件 | 商標 | プライバシー
Page view tracker