UniRxのシンプルなサンプルの取扱説明書
次(Subscribe)
Rx オーバービュー
UniRxのシンプルなサンプルはUniRxの小さいサンプルをよく使いそうな機能から順番に紹介していっています。
そんな感じで動作からRxを理解したいなという意図の入門記事集です。
(記事一覧 UniRxのシンプルなサンプルの取扱説明書)
ここではRxとは何かというのを簡単に解説してみます。
イベント
Rxの話の前に似た動きをするイベントについておさらいしてみます。
イベントとは、Aが起こったらBをするというような処理をするための考え方です。
たとえばボタンがクリックされたら…
たとえばテキストフィールドのテキストが変更されたら…
というような感じです。
それをそれぞれの言語ではこんな感じで書くわけです。
button.Click += _=>Console.Write("押された");
button.onClick.AddListener( () => Debug.Log("押された") );
$("button").bind("click", function(){
alert( "押された" );
});
このようにA(主語)が起こったらB(述語)を起こすのがイベントです。
これもイベント?
次に5秒たったらBを起こす
というのをイベントで実現できるでしょうか?
結構面倒臭いです。
さらに、ある変数xの値が変わったらBを起こす
というのはどうでしょう
もうちょっと面倒臭いです。
じゃあ、最初の3回は除いて5秒毎にBを起こす
は?
じゃあ、最初の3回は除いて5秒毎にある変数xが1以上であればBを起こす
は?
ここまでくるとif文が飛び交うイベントになるはずです。
たとえばこんな風に
/// *** Aの部分ここから *** ///
int counter;
//5秒毎にイベント出してくれるトリガー的なやつ(こんなものないよ)
//これの中にもカウンタなんかが結構入ってると思う
var trigger = new IntervalEvent(5);
trigger.Interval += _=>{
if(++counter < 3) return; //最初の3回スキップ
if(x <= 1) return; //xが1以上じゃないとダメ
/// *** Aここまで *** ///
Console.WriteLine("B実行"); // Bは実はここだけ
}
trigger.CountStart();//カウンタースタート的な?
Aの条件がどんどん増えていくと本当のやりたいことBが見にくくなっていきます。
主語は結局Aが起こったらという抽象レベルでは同じことなはずです。
ここで新しくRxというツールを導入することでこの複雑な条件をスマートに解決できるようになります。
Rxとは
Rxとは.NetのObserverパターンの実装です。
Observerパターンは簡単に言ってしまえば、何かが起こった時にそれに伴って起きてほしい動作を登録するためのデザインパターンです。
もっと簡単にいえば強力なイベントです。
次で簡単な例を示してみます。
簡単なRx
先ほどの例をRxに直してみます。
まず5秒毎にはこう書きます。
using System;
Observable.Interval(TimeSpan.FromSeconds(5)) //5秒毎
さらに最初の3回はスキップするを追加するとこうなります。
Observable.Interval(TimeSpan.FromSeconds(5)) //5秒毎
.Skip(3) //最初の3回スキップ
さらにさらに、xが1より大きいだとこうです
Observable.Interval(TimeSpan.FromSeconds(5)) //5秒毎
.Skip(3) //最初の3回スキップ
.Where(_=> x >= 1) //xが1以上
このようにRxはメソッドチェーンで条件をつなげることができます。
これの素晴らしいところは
* Skipはスキップのため
* Whereはフィルタリングのため
というように一目見て役割がわかるということです。
最後にBをやるですが
Observable.Interval(TimeSpan.FromSeconds(5)) //5秒毎
.Skip(3) //最初の3回スキップ
.Where(_=> x >= 1) //xが1以上
.Subscribe(_=>Console.WriteLine("B 実行")); //実行
このようにRxではSubscribeというメソッドで表します。
これももちろんSubscribe=B(述語)であるという意味をはっきりと示しています。
いろいろなRx
今回挙げた色々なAはRxでは次のように対応します
* ボタンが押された・・・FromEventやUnityだと onClick.AsObservable()
* 一定時間毎に・・・Interval
* ある値xが変化した・・・ReactiveProperty
ほかにもボタンAとボタンBのどちらかが押された時や
ボタンA,Bの両方が1回以上押された時
ボタンAが押されたあとBが押された時
ボタンAが押されて10秒後
などもRxでは簡単に実現することができます。
Rxのいいところ
- 合成可能(WhereとかSelectなんかのLINQ形式の処理ができます)
- クリックから値の変更まですべて同じように処理することができる
- デフォルトで用意されている挙動が多い
- 使うだけなら簡単(イベントみたいに使えます)
- 自分で作るのもそこまで難しくない(Subjectとか使えば簡単にできます)
- クラスメンバを使わずに状態を持つことができる
- 処理の後付(条件を満たした時にだけSubscribeで登録する)が自然にできる
UniRxのシンプルなサンプルはそれを一つずつ動作を確認していくものです。
RxではなくUnity用のRxであるUniRxですが結局概念自体は変わらないのでどこでも応用ききますよ。
書いてる本人も勉強中です。