概要
AngularにおけるRxJSを利用したObserver patternはRxJSの基礎であると共に、躓きやすいポイントの一つです。
大体書いた直後とかは何やっているか理解できるけど、しばらくたって同じコードを見ると「Subjectって何やってるんだっけ?」「subscribeがどこにも見当たらないんだが?」「Observer? Observable?」みたいな状態なってしまい、それを何回も繰り返してしまいます(サンプル数1)。
このドキュメントを通して、AnbularでのObserver patternにおける登場人物が何をやっていて、お互いにどういう風に関連しあっているのかを整理をして行きたいと思います。
Observer pattern?
Observerパターンとはデザインパターンの一種です。wikipediaで書かれているのは「プログラム内のオブジェクトのイベントを他のオブジェクトへ通知する処理」とのこと。自分はこの説明を聞いたとき具体的に何ができるのか今一想像できませんでした。
それよりも私はpublish/subscriber patternの一部と言われたほうがイメージがしやすかったです。
publish/subscriber
publish/subscribeとは「メッセージの送信者(publisher)が特定の受信者(subscriber)を想定せずにメッセージを送るようプログラムされたものである。」とwikipediaにあります。プログラムに限らずこのモデルは様々な所で利用されており、メーリングリストなどは一番有名なpublish/subscribeer patternの利用用途ですね。
Observer patternはその中でpublisherが管理しているオブジェクトの変更の通知をsubscriberが購読(subscribe)するという特殊な用途の一つなのではないかなと考えています。
全体図
このObservable patternでデータがどのように流れるかの概略図は以下になります。
Publisherが監視しているObjectに変更があった場合にひとつのPublisherから複数のSubscriberに「データがAからBに変わりましたよ」というデータが一方的に流れるようなデータの流れをします。
これはデータを取得したいSubscriberはポーリングなど積極的にデータの変更を検知する努力をする必要がなく、ただSubscriberは口を開けて待っているだけでPublisherが「AからBに変更したよ」という情報を送ってくれることになります。やばいですね。
では一体どうやって実現しているのでしょうか。
上の図よりももうちょっと内部実装よりな図が以下になります
この図を元にデータの受け取り側(Subscriber)と送り側(Publisher)が何をしているのか見ていきましょう。
Subscriber(Consumer)は何をしているの?
登場人物その1。Subscriberは最終的にPublisherから値を受け取りたいのです。
そのためには以下の2ステップを踏みます。
- observerを定義
- そのobserverをpublisherに登録(購読)
observerとは
observerとはnext()
, error
, complete()
を実装した関数を持つオブジェクトです。
next
は変更検知したというデータを受け取ってPublihserが実行するハンドラーで、例えばこのnextハンドラーを通じてSubscriberAが持っているObjectに変更を反映させるということもできます。
error
はなにかエラーが発生したときに実行するハンドラー(実装は任意)
complete
は実行が完了したときに実行されるハンドラー(実装は任意)
この定義したハンドラーは値の変更が通知されたときにSubscriberがその値をどうしたいのかが定義されています。
observerをPublisherに登録する(購読する)
定義したobserverはPublihserに登録します。
Angular(RxJS)でよく見るsubscibe(observer)
がまさにその購読処理になります。
Publisherは何をしているの?
登場人物その2。PublisherはSubscriberが登録したハンドラーを監視しているオブジェクトの変更をトリガーに実行します。RxJSではObservableというインスタンスのsubscirbe関数にSubscriberが定義したobserverを渡すことで実現します。
Observableとは
Observableは以下のことをしてくれます。
- データを流す
- そのデータを流したときに実行する関数(observer)を登録する。
データを流す
このデータの流れは色々な所から取得することができ、それはhttpリクエストだったりとか、イベントだったりとか、またRxJSならSubjectを利用すればnext
関数でデータを流すこともできます
Publisherは以下のことをします。
- 監視対象のオブジェクトの変更を検知
- 登録されているSubscriberのハンドラーを実行する。
- この登録される関数はいくつでも登録可能なので1対Nの通信(一方的にデータを垂れ流すだけですが)が可能
- 1はPublisherでNはSubscriber。
- この登録される関数はいくつでも登録可能なので1対Nの通信(一方的にデータを垂れ流すだけですが)が可能
Angularにおける実装
TBD
なんか文章量も多くなってきたし、別で書くかも