yano3nora
7/2/2017 - 1:46 PM

[riot: observable] Implement Observer pattern by riotjs. #riot #js

[riot: observable] Implement Observer pattern by riotjs. #riot #js

Observer pattern ?

Javaに専用ライブラリがあるなど古くからある伝統的なデザインパターン。観察される側(=Subject)と観察する側(=Observer)の2つの役割が存在し、Subjectの状態が変化した際にObserverに通知され、関連する処理が実行されていく(多くは通知とともにコールバックを受け付ける)。MVCモデルにおけるMV間の関係性(イベント/アクションへのリアクション)など、外部イベント駆動で連鎖的に動作する機能の実装で利用される(→イベント駆動型プログラミングと相性よい)。

どちらかというと観察よりも「通知」に重点が置かれており、Observerが通知を待っているので発行・購読パターン(Publish-Subscribe)とも呼ばれる。

References

http://qiita.com/shoheiyokoyama/items/d4b844ed29f84a80795b http://qiita.com/varmil/items/8cd8fe9da510e31d940a http://d.hatena.ne.jp/backpaper0/20111111/1321012118


Observable of Riot

  1. Observable (通知・監視オブジェクト) の生成 var obs = riot.observable()
  2. タグのマウント時、第二引数にオブザーバをぶっこむ
    • riot.mount() の第二引数に入れたものは opts でとれる
    • `riot.mount('hoge', {obs: obs});
  3. タグは opts から Observable を受け取り自身にセット this.obs = opts.obs
  4. on メソッドリスナー登録 `this.obs.on('refresh', function(args) {...}
  5. 外部から trigger でイベント発火→通知 `this.obs.trigger('refresh', data);
  6. (3) のリスナーが通知を受け取りコールバック実行

references

http://riotjs.com/ja/api/observable/ https://goo.gl/6mYvol https://goo.gl/Vsk2j3

api

/**
 * riot.observable()
 * イベントのトリガ発火および監視を司る新規オブザーバ生成。
 */
var obj = riot.observable()


/**
 * el.on(events, callback)
 * イベント監視
 */
el.on('start', function(args) {
  // start という1つのイベントを監視
})
el.on('all', function(event, param1, param2) {
  // すべてのイベントを監視
  // eventはイベントの名前
  // パラメータによってここで何かをする
})


/**
 * el.trigger(event, arg ... argN)
 * eventを監視しているすべてのコールバック実行
 */
el.on('start', function(engine_details, is_rainy_day) {
  // startイベントを監視して、引数を待ち受け
})
// 引数とともに、startイベントをトリガー
el.trigger('start', { fuel: 89 }, true) 


/**
 * el.one(events, callback)
 * eventsを監視して一度だけcallbackを実行
 */
el.one('start', function() {
  // 'start'が何回発火されても、一度だけ実行する
})


/**
 * el.off(events)
 * events の監視解除
 */
el.off('start')
el.off('*')
  // 全解除
el.off('start', doIt) // 特定のリスナを削除


Sample Code

// app.js
var obs = riot.observable();
riot.mount('listener', {obs: obs});
riot.mount('trigger', {obs: obs});

// listener.tag
<bar>
  <input type="text" name="hoge">
  <script>
     this.obs = this.opts.obs
     obs.on("myEvent", (text) => {
     this.hoge.value = text;
     this.update();
    });
  </script>
</bar>

// trigger.tag
<foo>
  <input type="text" onchange={ this.inputted }>
  <script>
    this.obs = this.opts.obs
    this.inputted = (e) => {
      var text = e.target.value;
      this.obs.trigger("myEvent", text);
    };
  </script>
</foo>