WPF/Silverlightの特徴と一般的な設計原則から導出する MVVM(Model/View/ViewModel)パターン わんくま同盟 東京勉強会 #60 尾上 雅則 尾上 雅則(おのうえ まさのり) ◦ 昭和58年度生 フリーランス 使用技術 ◦ C#er ◦ WPF/Silverlight・ASP.NET・WindowsFormsなど。 ◦ AzureとかASP.NET MVCとか覚えたい。 MVVMer。MVVM星人とか呼ばれたりもします。 Blog : the sea of fertility http://ugaya40.net Twitter : @ugaya40 WPF/Silverlightの特徴と、 一般的な設計原則から WPF/Silverlightのための設計パターンである MVVMパターンを導出して、 MVVMパターンはなんら特別なパターンではない という事を理解して頂きます。 また、インフラの必要性についても話します。 WPF/Silverlightの考慮すべき特徴の紹介 WPF/Silverlightアプリの設計定石を考える(1) WPF/Silverlightアプリの設計定石を考える(2) WPF/Silverlightアプリの設計定石を考える(3) まとめ ◦ 見た目と機能の分離 ◦ 一般的な設計原則から ◦ WPF/Silverlightの特徴から、そしてMVVMパターン へ ◦ リッチクライアントだから考えなくてはならない事 ControlTemplate VisualStateManager 双方向データバインド • DataTemplate • • • 同じコントロールも外観をXAMLだけで別の外見に。 <TreeView> <ListBox> 画像貼りミス じゃないんですよ! 外見の変化はカスタムコントロールを作る動機ではなくなった。 コントロールに状態に応じた外観を定義する事が可能 になった。(状態間にアニメーションの定義も可能/状 態を追加する事も可能) 外観に関わるコードはこうやってほぼ全てXAMLに委 譲できる。 WPF/Silverlightのデータバインディングは双方向の データバインドに対応している コレクションコントロール(ListBox/TreeView)などに は最強の武器がある。 WPF/Silverlightでは見た目に関する定義をほとんど XAMLに委譲できるようになっている。 データバインドが見た目と機能の分離をさらに促進す る。 データバインドに頼らないで作ろうとすると動作に制 約がつく。 ◦ たとえばC#/VBコードから構築されたDataTemplateでは Templateのすべての機能を使用する事ができない旨がMSDN に明記されている http://msdn.microsoft.com/ja-jp/library/ms602715.aspx 一般的な設計原則から • レガシーなイベントドリブン コードの問題点 • 相互依存 • ざっくりとした一般的なGUI 責務分割型設計 イベントハンドラに全ての処理を書くと、イベントの発 生順序とビジネスドメイン(アプリ本来の問題領域)の処 理が強く結合してしまいやすい。 アプリ本来の処理シーケンスと、見た目のコード の混在を片づけるには、そりゃあ責務を分離すれ ば良いんです。 ◦ しかし気を付けなければならない事があります。 ◦相互依存です。 相互依存とは ◦ 分割された責務が、互いが互いに依存する事。 互いが互いに依存する事で単一責任の原則に反し やすくなる。 インターフェースによるアプローチ ◦ 相手がインターフェースを実装している事だけを知って いれば良い。 OOPでの疎結合の基本。 イベントでのObserverパターンによるアプローチ ◦ Observeとは監視するという意味。 ◦ イベント受信側について、イベント発行側が全く知る必要がない。 責務間の関連が深い(通信相手の存在が前提)場合 がシンプルなinterfacceの方が良い。 ◦ 記録処理クラスと、記録の実体(ファイル・DB)クラスの 通信 ◦ いわゆるリポジトリパターン 責務間に関連が無い場合はイベントObserverに よるアプローチが良い ◦ 完全に責務に関連がない場合、通信相手の存在を前提と したシンプルなinterfaeよりObserverの方が優秀。 ここまでを踏まえて、GUIアプリをざっくり分け てみます。 呼出 外観 ビジネスドメイン (アプリの機能) イベント通知 ビジネスドメインから外観への通信は イベントの方が望ましい ここまでを踏まえて、GUIアプリをざっくり分け てみます。 呼出 外観 View ビジネスドメイン イベント監視 イベント通知 Model 実はこれがMVCに代表されるUIパターンの共通 理念であり、基本的な形。 呼出 View イベント監視 イベント通知 Model 全てのUIパターンの正しい理解のためには、この 形を理解する事が基本です。あとでも出てくるの で覚えておいてください。 呼出 View イベント監視 イベント通知 Model WPF/Silverlightの特徴から、 そしてMVVMパターンへ • コレクションコントロールの罠 • イベントの発生順序とコントロー ルの状態の複雑化 • 別途状態ストアを持とう! • MVVMパターン コレクションコントロールには罠がある。 ◦ ListBox/ListView コレクションコントロールには罠がある。 ◦ TreeView 展開するまで やはり子のインスタンス が無い! DataTemplate内の別のコントロールの情報をと りにくい VisualTreeHelperとかいう静的クラスの、 ◦ 自分の子の数を習得するだけのメソッドと ◦ インデックスで対象の子コントロールを取得してくるだ けのメソッド ◦ でしか、DataTemplate内のコントロールは触る事がで きない。。。有り得ない。。。 ではどうするか → データバインドで全て解決 各項目に対応するような 表示用のデータバインド用オブジェク トがあれば全てデータバインドで解決 できる (チェック状態などもboolとして持つ) むしろ他のアプローチじゃ解決できない! WPF/Silverlightではコントロールはとことん データバインド前提で作られている。 コレクションコントロール以外でも、レイアウト 関連プロパティなどでは、イベントの発生状況に よってプロパティの値が信用できない。 WinForms/ASP.NETまではむしろデータバイン ドはおまけ機能の印象が強かった。 WPF/Silverlightではデータバインドこそが本流。 使わないと制約だらけ。 ◦ コントロールの状態(プロパティ)を、ビジネスド メイン呼び出しのための状態判断に信用しない方 がよいのが、WPF/Silverlight。 ◦ コントロールの状態は、レイアウトシステムとの 連携やコントロールの内部実装で使用する事にな る。 ◦ だから・・・・ コレクションコントロール以外のものも含めて、画 面のレンダリングに必要な動的に変化する情報を保 存する責務を新たに設ける。 バインド用オブジェクト ● ● テキスト:1992 バインド! ● ● 選択されているかどうか ● テキスト:1993 ● ● 選択されているかどうか ● ● 画面を描画するための状態ストアを別途持ってしま おう! 外観 画面 XAML Data Binding 画面を レンダリングする ための状態ストア つまりこれが・・ 呼出 ビジネス ドメイン (アプリの機能) 外観 イベント 外観 呼出 Data Binding 画面 画面を レンダリングする ための情報 ビジネス ドメイン (アプリの機能) イベント View : UIの外観と構造を定義 ViewModel : Viewをレンダリングするための情報 Model : アプリ本来の問題領域に対するコード 呼出 画面 View Data Binding レンダリング情報 ビジネス ドメイン ViewModel Model イベント この形の事をMVVMパターンと言います。見ての 通り、なんら難しいパターンでも、特別なパターン でもないのです。 依存 Data Binding View ViewModel Model イベント リッチクライアントだから考えな ければいけない事 • • • 責務間通信に関わる問題 インフラストラクチャの使用 通信手法の統一がもたらすも の リッチクライアント開発では、リッチクライアント だからこそ考えなければならない問題があります。 WinFormsなどの開発で、開発の最後の方まで残り がちで解決の厄介なバグ、覚えがありませんか? 代表的な一例 そう メモリリーク です。 そもそもメモリリークとは イベント 受信側A public class イベント受信側A { ButtonA.Click += Clicked; イベント 発行元 ButtonA private void Clicked(object sender, RoutedEventArgs e) { //処理 Click イベント公開 そもそもメモリリークとは イベント 受信側A public class イベント受信側A { 実は発行元(Button A)が ButtonA.Click += Clicked; 受信側AのClickedメソッ ドの参照を保持している private void Clicked(object sender, RoutedEventArgs e) { //処理 イベント 発行元 ButtonA Click イベント公開 そもそもメモリリークとは イベント 受信側A public class イベント受信側A イベントの登録を解除しないで、 { 受信側が勝手に消滅しようとし ButtonA.Click += Clicked; ても発行側に参照されているの で消えられない! private void Clicked(object sender, RoutedEventArgs e) { //処理 イベント 発行元 ButtonA Click イベント公開 つまりメモリリークとは イベントを公開しているオブジェクトがあり、発行 元より寿命の短いオブジェクトがイベントを受信し ている時に起きやすい問題。 きちんと登録を解除できれば良いけど、 WPF/Silverlightではそのタイミングの管理が非常 に面倒。 ちなみにWebでは滅多に発生しない問題。 Webではすべてのオブジェクトの生存期間が基本的 に1リクエストの中に納まるから、分けた責務のオ ブジェクト全てがほぼ同時に生成され、ほぼ同時に 消滅する。(static使用時を除く) ステートフル(状態を持つ・持ち続ける)アプリ、つ まりほとんどの場合リッチクライアントに固有の問 題! MVVMパターンでのメモリリークについて、 それぞれ View ⇔ ViewModel間 ViewModel ⇔ Model間 ◦ コレクションコントロールの中身とか、頻繁にイ ンスタンスが出来たり消えたりしています。 ◦ 検索結果画面など、一時的な画面はWindow消す 時に普通ViewModelも捨てちゃいます。 についてみていきます。 データバインディング機構の正体 Data Binding View ViewModel データバインディング機構とは リフレクションなど View Data Binding イベントによる 変更通知 ViewModel しかし、データバインディング機構内部では WeakEventパターン(後述)が適用され、メモリ リークのリスクがありません。 リフレクションなど View ViewModel イベントによる 変更通知 逆に言えば、データバインディング機構から漏れた 通信手法を使用する事でメモリリークのリスクがあ ります。 リフレクションなど View ViewModel イベントによる 変更通知 ViewModelとModelの間の通信にはデータバイン ディング機構などが介在しません。一般的なメモリ リーク対策を取る事になります。 呼出 ViewModel Model イベント通知 そこでWeakEventパターンです。 リフレクションなど ViewModel Model イベント通知 WeakEventパターンとは弱いイベントパターンの 事です。関連クラスはSystem.Windows名前空間 に定義されていて、WPFなどでの使用が考慮され ているように見えます。 MSDNによれば http://msdn.microsoft.com/ja-jp/library/aa970850.aspx 弱いイベント パターンは、リスナーをイベントに 登録する必要がある際に、いつ登録を解除するか を明示的には認識できない場合に使用できます。 ええ、まさにうってつけです。 端的に言えば、イベントを受 ける代理のオブジェクトを立 て、そのオブジェクトをグ ローバルに弱参照で管理する 事によってCLRにイベントハ ンドラを参照と認識させない パターン 端的に言えば、イベントを受 ける代理のオブジェクトを立 いちいち実装とか説明とか て、そのオブジェクトをグ やっていられないレベルで ローバルに弱参照で管理する 面倒なので説明省略 事によってCLRにイベントハ ンドラを参照と認識させない パターン とにかくリッチクライアントは、 ステートフルであるがゆえに 適切に作成するには、ある意味 ではWebより深い知識が要求さ れます。 要はこんな事を 自分で考えたくないんです! チームメンバーに全て理 解してもらえますか? 既存の MVVM補助インフラストラクチャ を使えば、 そんな事自分で理解する必要も 考える必要もないんです! Livet ◦ http://ugaya40.net/livet ◦ 作者: 僕 ◦ WPF4専用。補助ライブラリとしての機能の他に各種VS用テンプ レート・スニペット・Expression Blend デザイナ拡張機能など を持つ。 ◦ もうすぐver 1.0 Prism ◦ ◦ ◦ ◦ http://compositewpf.codeplex.com/ 作者:MS Pattern & Practiceチーム WPF3.5/4 Silverlight4用。純粋な補助ライブラリ。 外部の方がテンプレートなどを提供してくれている。チュートリ アルなどもある。巨大。 MVVM Light Toolkit ◦ http://www.galasoft.ch/mvvm/ ◦ 作者:Laurent Bugnion ◦ WPF3.5/4 Silverlight4 WindowsPhone 7用。おそらくは世界 で一番利用者が多いライブラリ。補助ライブラリとしての機能の 他に各種テンプレート・スニペットなどを持つ。 私見では現状ではWPFならLivet一択。 SilverlightならMVVM Light Toolkitでコードビ ハインドありをおすすめします。Windows Phone 7 ではMVVM Light Toolkitしか選択肢が ないのが現状です。 ViewModel⇔Model間通信で提供される機能 ◦ MVVM用にカスタマイズされたWeakEventの実装 ◦ Livet Notificator/ViewModelHelper/NotificationHelper ◦ Prism EventAggregator ◦ MVVM Light Toolkit Messenger View⇔ViewModel間通信で提供される機能 ◦ 通信手法のデータバインドへの統一 ◦ メソッドのバインディング DelegateCommand/RelayCommand ◦ XAML機能の拡充 ビヘイビア・トリガー・アクション ◦ 揮発性の現象への対応 メッセージングシステム (補足)View⇔ViewModel間通信 ◦ コードビハインド無し云々を聞いた事がある 方もいらっしゃると思いますが、それはView とViewModel間の通信をデータバインドに統 一する事によって生まれる付随的なメリット です。それがMVVMパターンの目的であるわ けではありません。 (補足)View⇔ViewModel間通信 ◦ コードビハインドを失くす事で、管理面(責務 の遵守が容易に)、XAMLのXMLたるメリット (WYSIWYGなエディタとの相性とか)を活か しやすくなります。 ◦ コードビハインドを失くすのが目的ではなく、 データバインドに通信を統一する事で、考慮 事項を減らし、MVVM本来のメリットを引き 出そうとするのが目的! 外部ライブラリを使うのは敷居が高 い? それは無い。 スキルが低い人間が混じるからこそ、イ ンフラが必要。(WeakEventとかみんな が理解できるもの?) 特別なパターンどころか、 むしろWPF/SLにとって一択ってくらい普通のパターン 外観 画面 呼出 Data 画面を Binding レンダリングする ための情報 ビジネス ドメイン (アプリの機能) View ViewModel Model イベント 責務 ◦ View:UIの外観と構造を定義 ◦ ViewModel :UIレンダリングのためのデータストア ◦ Model : アプリ本来の問題領域を表すコード 責務間の通信 ◦ View⇔ViewModel : 極力双方向データバインディン グで。インフラの導入具合によっては全てデータバイ ンディングに統一する事も可能。 ◦ ViewModel⇔Model : イベントとメソッド呼び出し 各種MVVMインフラが提供する機能は、 WPF/SilverlightでMVVMパターンの持つ思想の メリットをより引き出したり、面倒な考慮事項 を失くすためのもの。DelegateCommand使う からMVVMとか、コードビハインド無いから MVVMとか勘違い。 スキルに自信がないからこそMVVMインフラを 使う。 MVVMで良く聞く具体的な実装要素 (DelegateCommandとか)のうち、何を使えば どういうメリットがあり、使わなければどんな メリットが損なわれるかを把握する事で実務で の導入をしやすくする。 @IT MVVMパターンの常識 「M」「V」「VM」の役割とは? http://www.atmarkit.co.jp/fdotnet/chushin/greatblo gentry_02/greatblogentry_02_01.html MVC/MVP/PMなどの、別のUIパターンとの違 いを学ぶ。 the sea of fertility MVVMパターンとイベント駆動開発、そして MVC/MVP/PMパターンとの関係 - 何故MVVMなのか http://ugaya40.net/wpf/mvvm-mvc-mvp-pmeventdriven.html .NET/Silverlight標準、MVVM Light Toolkit/Prism/Livetなどを採用した場合の何を どこまで学べば良いかのガイドライン。 the sea of fertility MVVMパターン学習のファーストステップ - 何をどこま で勉強するか http://ugaya40.net/mvvm/mvvm-first.html 以下の方々に 簡易レビュー協力頂きました。 ありがとうございます。 秘密組織 謎クエリの会(3名) @xin9leさん
© Copyright 2024 ExpyDoc