かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ReactivePropertyを使ってみた感想 イケテル!気持ちいい!ハードルは高い?

# 変更履歴
2011/10/17 コメントの指摘のとおり敷居が高いをハードルが高いに修正しました。

id:neueccさんの作ったReactivePropertyが最近アツイので、今チマチマ作ってるWindows Phone 7のアプリケーションでも途中から組み込んで使ってみました。まだアプリは未リリースなのですが、使ってみた感想とかをツラツラと書いてみようと思いました。

ReactivePropertyの基本的なアプローチ

ReactivePropertyは、WPF/Silverlight/Windows Phone 7でのアプリケーションの開発でReactive Extensionsの特徴であるIObservableやIObserverを使ってModelとViewModelとView(おまけ程度)で統一的な記述ができるようにしてくれるライブラリです。(あくまで私が触って感じた感想なのでneueccさんの思いとしては違うかもしれません。)IObservableは、IEnumerableとかTaskとかその他様々なものから変換可能なので、非常につぶしのきくインターフェースです。ReactivePropertyがとっているアプローチとしては、プロパティを下記の記事のようにHogehogeFieldやHogehogePropertyのように値をラップする型で定義する方法をとっています。

ReactivePropertyでは、ReactivePropertyという型でMVVMパターンでいうところのViewModelのプロパティを定義するという特徴があります。このReactivePropertyがIObservableを実装していてReactivePropertyのValueプロパティをセットする度に対象のReactivePropertyを監視しているIObserverのOnNextが呼ばれるようになっています。
このReactivePropertyですが、IObservableからの作成することも可能です。そのためIObservableからReactivePropertyを作って、そいつの変更を受け取って加工したり、別のシーケンスに流し込んだり様々なことができるようになっています。さらに、コマンドやObservableCollectionもIObservableから作成できるようになっています。そして、コマンドやコレクションもIObservableとして扱うことができます。今まで別々に扱ってきたプロパティ、コレクション、コマンドを統一的に扱える、さらにはModelもIObservableを返すようにするとModelともシームレスに繋がるという書いているだけでもワクワクするようなコードがかけちゃいます。
例は、ReactivePropertyのページからダウンロードしてサンプルを見てみるといいと思います。あと、直近の自分のBlogの記事で書いたコードですが、どれだけ強力にいろんなものと統合できるかなんとなくわかると思います。

// LINQ Padで実行
// 初期化して読み込む
var load = new ReactiveCommand();
// 続きを読み込む
var loadNext = new ReactiveCommand();
// 結果をためておくコレクション
var collection = default(ReactiveCollection<string>);


collection = Observable
    .Merge(
        load.Do(_ => collection.Clear()), // loadコマンドはコレクションをクリアして続きの処理をやる
        loadNext) // loadNextはコレクションはいじらずに続きの処理をやる
    .Select(_ => Enumerable.Range(1, 5).ToObservable()) // データとって
    .Switch()
    .Select(i => string.Format("{0}歳", i)) // 加工して
    .ToReactiveCollection(); // コレクションにするよ

// 初期状態の出力
collection.Dump();

// 最初の読み込み
load.Execute(null);
collection.Dump();

// 続きのデータの読み込み
loadNext.Execute(null);
collection.Dump();

// データを初期化して読み込み
load.Execute(null);
collection.Dump();

実行結果

# 実行結果 #で始まる行は私が追記してます
# 初期状態では0件
ReactiveCollection<String> (0 items) 

# loadコマンドを実行すると5件読み込まれる
5ReactiveCollection<String> (5 items)  
1歳
2歳
3歳
4歳
5歳
 
# loadNextコマンドを実行するとつづけて5件読み込まれる
5ReactiveCollection<String> (10 items)  
1歳
2歳
3歳
4歳
5歳
1歳
2歳
3歳
4歳
5歳
 
# loadコマンドを実行すると中身がクリアされてデータが読み込まれる
5ReactiveCollection<String> (5 items)  
1歳
2歳
3歳
4歳
5歳

この方法の不満点

とまぁ非常に強力で素敵なReactivePropertyですが、このアプローチをとったときの個人的な不満点として以下の点があります。

  • POCOのプロパティを前提にしたツール、ランタイム、コントロールのサポートを受けることができない

上記一点に限ります。たとえば、DataGridやDataForm(Silverlight Toolkit)ではプロパティと、それにつけた属性にもとづいて自動的に画面を構築してくれます。こういった機能は、個人的には今後どんどん強化されていってほしいなと思っているのですが、ReactivePropertyのようなアプローチをとる場合には諦める必要があります。個人的にはDataGridやDataFormのほうにも列や画面を生成するときに使用する方法に割り込めるようなポイントを作ってほしいな〜と思います。(TypeProviderとかで頑張ればここらへんなんとかなるのかな?未確認)

最後に

さて、このReactivePropertyですがまだまだbetaの段階です。betaの段階でも使ってて気持ちいい感覚を与えてくれたりと、素敵な仕上がりになっています。コンセプトも素晴らしいと思うので、今後成長していってほしいなぁと思います!!
しかも、特定MVVMライブラリに依存しないので、どんなMVVMライブラリと組み合わせても基本的に使えるというのも素敵なところです。ただし、MVVMライブラリがPOCOライクなプロパティを前提にしてる機能を提供している場合は上記の理由と同様に利用できないものがあるかもしれないので、使用するMVVMライブラリの提供する機能とReactivePropertyの機能を見比べて最適だと思う機能をチョイスしないといけません。ここらへん、MVVMライブラリにも精通しつつReactive Extensionsのことも知っててReactivePropertyの概要を把握してないといけない上に必要に応じてMVVMライブラリとReactivePropertyを繋ぐような機能を作りこまないといけないと思うので少しハードルが高いかもしれませんが、はまると開発効率は上がると思います。

ということで、MVVM + Reactive Extensionsというハードルの高い?世界へ踏み出したい人は是非使ってみましょう。因みに、ReactivePropertyはコンソールアプリケーションでも使えるので、もしかしてバッチ系のプログラムで使ってみても作者があっとおどろくようなことをできるかもしれませんね!