Rx on KO Rails！ 京王線でRxのストリームを感じようっ！！

# 動機
京王線に乗る機会がありました。そのときに駅にあった案内板の路線図をみました。
<img src="https://www.keio.co.jp/train/ticket/fare_chart/images/rosen.png"/>
PCを組み立てるときのケーブル配線みたいで、カラフルだし綺麗だなという印象です。同時にRxのストリームにも見えました。本記事は京王線の駅をRxのストリームにみたてたネタ記事です。
Rxを便利なプロミス程度の使い方しかしていない人は、Rxのストリームを感じて欲しいと思います。コードはKotlinで書きますがKotlin以外のRxユーザでも理解できると思います。特に難しいことはないと思います。

# 基本
```kotlin
Observable
  .just(Unit)
  .subscribe()
```
これがRxの流れの基本です。出力結果も何もないのですが、確かに通知が流れているのです。justで出発し、subscribeへ到達しています。このことを確かめるために、doOnNextを使いましょう。

```kotlin
Observable
  .just(Unit)
  .doOnNext(::println)
  .subscribe()
```
出力結果は、

```
kotlin.Unit
```
となっていて、確かにjustを出発しsubscribeへ到達したことが分かります。RxのデバッグプリントとしてこのdoOnNext技は便利です。Rxユーザの人は、是非、活用して欲しいと思います。

# 新宿駅から京王八王子駅まで
さて、いよいよ京王線にのってみましょう。まずは新宿から京王八王子まで乗車します。

```kotlin
Observable
        .just(Unit)
        .doOnNext { println("新宿駅") }
        .doOnNext { println("笹塚駅") }
        .doOnNext { println("代田橋駅") }
        .doOnNext { println("明大前駅") }
        .doOnNext { println("下高井戸駅") }
        .doOnNext { println("桜上水駅") }
        .doOnNext { println("上北沢駅") }
        .doOnNext { println("八幡山駅") }
        .doOnNext { println("芦花公園駅") }
        .doOnNext { println("千歳烏山駅") }
        .doOnNext { println("仙川駅") }
        .doOnNext { println("つつじヶ丘駅") }
        .doOnNext { println("柴崎駅") }
        .doOnNext { println("国領駅") }
        .doOnNext { println("布田駅") }
        .doOnNext { println("調布駅") }
        .doOnNext { println("西調布駅") }
        .doOnNext { println("飛田給（味の素スタジアム前）駅") }
        .doOnNext { println("武蔵野台駅") }
        .doOnNext { println("多磨霊園駅") }
        .doOnNext { println("東府中駅") }
        .doOnNext { println("府中駅") }
        .doOnNext { println("分倍河原駅") }
        .doOnNext { println("中河原駅") }
        .doOnNext { println("聖蹟桜ヶ丘駅") }
        .doOnNext { println("百草園駅") }
        .doOnNext { println("高幡不動駅") }
        .doOnNext { println("南平駅") }
        .doOnNext { println("平山城址公園駅") }
        .doOnNext { println("長沼駅") }
        .doOnNext { println("北野駅") }
        .doOnNext { println("京王八王子駅") }
        .subscribe()
```

当然、出力結果は以下の通り。単純。

```
新宿駅
笹塚駅
代田橋駅
明大前駅
下高井戸駅
桜上水駅
上北沢駅
八幡山駅
芦花公園駅
千歳烏山駅
仙川駅
つつじヶ丘駅
柴崎駅
国領駅
布田駅
調布駅
西調布駅
飛田給（味の素スタジアム前）駅
武蔵野台駅
多磨霊園駅
東府中駅
府中駅
分倍河原駅
中河原駅
聖蹟桜ヶ丘駅
百草園駅
高幡不動駅
南平駅
平山城址公園駅
長沼駅
北野駅
京王八王子駅
```

# 新宿駅から橋本駅まで
さて、京王線は調布駅から分岐して京王相模原線が出ています。Rxでストリームの分岐を表現しなければなりません。本記事ではストリームを感じてもらうことに主眼があるため、分岐についての詳細説明は
[RxのHotとColdについて](https://qiita.com/toRisouP/items/f6088963037bfda658d3) などを参照してください。

## Rxの分岐表現
ここからがRxのストリーム分岐の出番です。一般的なプログラミング言語の分岐といえばifやswitch等に相当しますが、Rxではshareとfilterの組み合わせで表現できます。

``` kotlin
(1..10).forEach {
    if(it % 2 == 0) { println("even $it"); val result = it + 8; println(result) }
    else { println("odd $it"); val result = it + 77; println(result) }
}
```

上記のkotlinで記述したものをRxで書き直すと以下になります（表示される順番は上のコードと下のコードでは違いますが、ここでは順番には関心がないとします）。

``` kotlin
Observable
        .range(1, 10)
        .share()
        .let {
            it.filter { it % 2 == 0 }.doOnNext { println("even $it") }.map { it + 8 }.subscribe(::println)
            it.filter { it % 2 != 0 }.doOnNext { println("odd $it") }.map { it + 77 }.subscribe(::println)
        }
```
偶数の流れと奇数の流れを感じられますか？

## 調布駅で分岐
準備もできたところで、調布駅で分岐させてみましょう。shareで分岐させます。

``` kotlin
val ps = PublishSubject.create<Unit>()
ps
        .doOnNext { println("新宿駅") }
        .doOnNext { println("笹塚駅") }
        .doOnNext { println("代田橋駅") }
        .doOnNext { println("明大前駅") }
        .doOnNext { println("下高井戸駅") }
        .doOnNext { println("桜上水駅") }
        .doOnNext { println("上北沢駅") }
        .doOnNext { println("八幡山駅") }
        .doOnNext { println("芦花公園駅") }
        .doOnNext { println("千歳烏山駅") }
        .doOnNext { println("仙川駅") }
        .doOnNext { println("つつじヶ丘駅") }
        .doOnNext { println("柴崎駅") }
        .doOnNext { println("国領駅") }
        .doOnNext { println("布田駅") }
        .doOnNext { println("調布駅") }
        .share()
        .let {
            it
                    .doOnNext { println("西調布駅") }
                    .doOnNext { println("飛田給（味の素スタジアム前）駅") }
                    .doOnNext { println("武蔵野台駅") }
                    .doOnNext { println("多磨霊園駅") }
                    .doOnNext { println("東府中駅") }
                    .doOnNext { println("府中駅") }
                    .doOnNext { println("分倍河原駅") }
                    .doOnNext { println("中河原駅") }
                    .doOnNext { println("聖蹟桜ヶ丘駅") }
                    .doOnNext { println("百草園駅") }
                    .doOnNext { println("高幡不動駅") }
                    .doOnNext { println("南平駅") }
                    .doOnNext { println("平山城址公園駅") }
                    .doOnNext { println("長沼駅") }
                    .doOnNext { println("北野駅") }
                    .doOnNext { println("京王八王子駅") }
                    .subscribe()
            it
                    .doOnNext { println("京王多摩川駅") }
                    .doOnNext { println("京王稲田堤駅") }
                    .doOnNext { println("京王よみうりランド駅") }
                    .doOnNext { println("稲城駅（駒沢女子大学最寄駅）") }
                    .doOnNext { println("若葉台駅") }
                    .doOnNext { println("京王永山駅") }
                    .doOnNext { println("京王多摩センター駅（サンリオピューロランド最寄駅）") }
                    .doOnNext { println("京王堀之内駅") }
                    .doOnNext { println("南大沢駅（首都大学東京最寄駅）") }
                    .doOnNext { println("多摩境駅") }
                    .doOnNext { println("橋本駅") }
                    .subscribe()
        }
ps.onNext(Unit)
```
とりあえず、分岐だけはしてみたコードです。出力結果は以下です。

```
新宿駅
笹塚駅
代田橋駅
明大前駅
下高井戸駅
桜上水駅
上北沢駅
八幡山駅
芦花公園駅
千歳烏山駅
仙川駅
つつじヶ丘駅
柴崎駅
国領駅
布田駅
調布駅
西調布駅
飛田給（味の素スタジアム前）駅
武蔵野台駅
多磨霊園駅
東府中駅
府中駅
分倍河原駅
中河原駅
聖蹟桜ヶ丘駅
百草園駅
高幡不動駅
南平駅
平山城址公園駅
長沼駅
北野駅
京王八王子駅
京王多摩川駅
京王稲田堤駅
京王よみうりランド駅
稲城駅（駒沢女子大学最寄駅）
若葉台駅
京王永山駅
京王多摩センター駅（サンリオピューロランド最寄駅）
京王堀之内駅
南大沢駅（首都大学東京最寄駅）
多摩境駅
橋本駅
```
いい感じです。ただし、このままだと京王八王子駅にも、橋本駅にも到着しています。
今はただ内容のない通知(「[RxJava(Kotlin)で通知内容が不要な通知にはUnitを使うと良いと思う](https://qiita.com/nakana/items/4360b0f170cb3be804e4)」参照のこと)を送ってますが、行き先駅を通知するようにして、きちんと行き先駅を通知してみましょう。

```kotlin
val ps = PublishSubject.create<String>()
ps
        .doOnNext { println("新宿駅") }
        .doOnNext { println("笹塚駅") }
        .doOnNext { println("代田橋駅") }
        .doOnNext { println("明大前駅") }
        .doOnNext { println("下高井戸駅") }
        .doOnNext { println("桜上水駅") }
        .doOnNext { println("上北沢駅") }
        .doOnNext { println("八幡山駅") }
        .doOnNext { println("芦花公園駅") }
        .doOnNext { println("千歳烏山駅") }
        .doOnNext { println("仙川駅") }
        .doOnNext { println("つつじヶ丘駅") }
        .doOnNext { println("柴崎駅") }
        .doOnNext { println("国領駅") }
        .doOnNext { println("布田駅") }
        .doOnNext { println("調布駅") }
        .share()
        .let {
            it
                    .filter { it == "京王八王子駅"}
                    .doOnNext { println("西調布駅") }
                    .doOnNext { println("飛田給（味の素スタジアム前）駅") }
                    .doOnNext { println("武蔵野台駅") }
                    .doOnNext { println("多磨霊園駅") }
                    .doOnNext { println("東府中駅") }
                    .doOnNext { println("府中駅") }
                    .doOnNext { println("分倍河原駅") }
                    .doOnNext { println("中河原駅") }
                    .doOnNext { println("聖蹟桜ヶ丘駅") }
                    .doOnNext { println("百草園駅") }
                    .doOnNext { println("高幡不動駅") }
                    .doOnNext { println("南平駅") }
                    .doOnNext { println("平山城址公園駅") }
                    .doOnNext { println("長沼駅") }
                    .doOnNext { println("北野駅") }
                    .doOnNext { println("京王八王子駅") }
                    .subscribe()
            it
                    .filter { it == "橋本駅"}
                    .doOnNext { println("京王多摩川駅") }
                    .doOnNext { println("京王稲田堤駅") }
                    .doOnNext { println("京王よみうりランド駅") }
                    .doOnNext { println("稲城駅（駒沢女子大学最寄駅）") }
                    .doOnNext { println("若葉台駅") }
                    .doOnNext { println("京王永山駅") }
                    .doOnNext { println("京王多摩センター駅（サンリオピューロランド最寄駅）") }
                    .doOnNext { println("京王堀之内駅") }
                    .doOnNext { println("南大沢駅（首都大学東京最寄駅）") }
                    .doOnNext { println("多摩境駅") }
                    .doOnNext { println("橋本駅") }
                    .subscribe()
        }
ps.onNext("橋本駅")
println("----------")
ps.onNext("京王八王子駅")
```

出力結果は以下。

```
新宿駅
笹塚駅
代田橋駅
明大前駅
下高井戸駅
桜上水駅
上北沢駅
八幡山駅
芦花公園駅
千歳烏山駅
仙川駅
つつじヶ丘駅
柴崎駅
国領駅
布田駅
調布駅
京王多摩川駅
京王稲田堤駅
京王よみうりランド駅
稲城駅（駒沢女子大学最寄駅）
若葉台駅
京王永山駅
京王多摩センター駅（サンリオピューロランド最寄駅）
京王堀之内駅
南大沢駅（首都大学東京最寄駅）
多摩境駅
橋本駅
----------
新宿駅
笹塚駅
代田橋駅
明大前駅
下高井戸駅
桜上水駅
上北沢駅
八幡山駅
芦花公園駅
千歳烏山駅
仙川駅
つつじヶ丘駅
柴崎駅
国領駅
布田駅
調布駅
西調布駅
飛田給（味の素スタジアム前）駅
武蔵野台駅
多磨霊園駅
東府中駅
府中駅
分倍河原駅
中河原駅
聖蹟桜ヶ丘駅
百草園駅
高幡不動駅
南平駅
平山城址公園駅
長沼駅
北野駅
京王八王子駅
```

きちんと、橋本駅行きは新宿を出発して橋本駅に到着し、京王八王子駅行きは新宿を出発して京王八王子駅に到着していますね。

# さいごに、競馬場線、動物園線、そして高尾線も加えてみます
京王新線とか京王井の頭線は、今回見送らせていただきました。

```kotlin
val ps = PublishSubject.create<String>()
ps
        .doOnNext { println("新宿駅") }
        .doOnNext { println("笹塚駅") }
        .doOnNext { println("代田橋駅") }
        .doOnNext { println("明大前駅") }
        .doOnNext { println("下高井戸駅") }
        .doOnNext { println("桜上水駅") }
        .doOnNext { println("上北沢駅") }
        .doOnNext { println("八幡山駅") }
        .doOnNext { println("芦花公園駅") }
        .doOnNext { println("千歳烏山駅") }
        .doOnNext { println("仙川駅") }
        .doOnNext { println("つつじヶ丘駅") }
        .doOnNext { println("柴崎駅") }
        .doOnNext { println("国領駅") }
        .doOnNext { println("布田駅") }
        .doOnNext { println("調布駅") }
        .share()
        .let {
            it
                    .doOnNext { println("西調布駅") }
                    .doOnNext { println("飛田給（味の素スタジアム前）駅") }
                    .doOnNext { println("武蔵野台駅") }
                    .doOnNext { println("多磨霊園駅") }
                    .doOnNext { println("東府中駅") }
                    .share()
                    .let{
                        it
                                .doOnNext { println("府中競馬正門前駅（東京競馬場前）") }
                                .subscribe()
                        it
                                .doOnNext { println("府中駅") }
                                .doOnNext { println("分倍河原駅") }
                                .doOnNext { println("中河原駅") }
                                .doOnNext { println("聖蹟桜ヶ丘駅") }
                                .doOnNext { println("百草園駅") }
                                .doOnNext { println("高幡不動駅") }
                                .share()
                                .let {
                                    it
                                            .doOnNext { println("多摩動物公園駅") }
                                            .subscribe()
                                    it
                                            .doOnNext { println("南平駅") }
                                            .doOnNext { println("平山城址公園駅") }
                                            .doOnNext { println("長沼駅") }
                                            .doOnNext { println("北野駅") }
                                            .share()
                                            .let{
                                                it
                                                        .doOnNext { println("京王八王子駅") }
                                                        .subscribe()
                                                it
                                                        .doOnNext { println("京王片倉駅") }
                                                        .doOnNext { println("山田駅") }
                                                        .doOnNext { println("めじろ台駅") }
                                                        .doOnNext { println("狭間駅") }
                                                        .doOnNext { println("高尾駅") }
                                                        .doOnNext { println("高尾山口駅") }
                                                        .subscribe()
                                            }
                                }

                    }
            it
                    .doOnNext { println("京王多摩川駅") }
                    .doOnNext { println("京王稲田堤駅") }
                    .doOnNext { println("京王よみうりランド駅") }
                    .doOnNext { println("稲城駅（駒沢女子大学最寄駅）") }
                    .doOnNext { println("若葉台駅") }
                    .doOnNext { println("京王永山駅") }
                    .doOnNext { println("京王多摩センター駅（サンリオピューロランド最寄駅）") }
                    .doOnNext { println("京王堀之内駅") }
                    .doOnNext { println("南大沢駅（首都大学東京最寄駅）") }
                    .doOnNext { println("多摩境駅") }
                    .doOnNext { println("橋本駅") }
                    .subscribe()
        }
```