Infinito Nirone 7

白羽の矢を刺すスタイル

RxJava において Observable#hide() とは何者か

Observable#hide() の Javadoc にある説明は次の通り。

Hides the identity of this Observable and its Disposable.

Allows hiding extra features such as Subject's Observer methods or preventing certain identity-based optimizations (fusion). ... 中略 ... Returns: the new Observable instance

ぱっと見た限りは「いつ使うのか分からんな…」という感じなのですが、この文で例示されているSubject がもつ Observer インタフェースのメソッドを隠蔽するという部分と、hide() が新しい Observable を返すという部分がミソで、次の StackOverflow にある回答がまさにこの Javadoc の言いたいことになります。

stackoverflow.com

Subject は Observable のサブタイプなので、Subject を Observable として外部に公開するときはそのまま Observable にキャストして公開できます。

class Something {

  private val subject: Subject<Something> = PublishSubject.create()

  fun observeSomething(): Observable<Something> = subject

}

しかしその実体は Subject のままなので、公開 API で受け取った Observable を Subject に明示的にキャストして使えます。

class Client(val something: Something) {

  fun doSomething() {
    val observable = something.observeSomething() // this observable is actually a subject
    val subject = observable as Subject // no failure
  }
}

およそ Subject を Observable として公開する場合、それを使う側であえて Subject にキャストし直して使われることは意図しない使い方になると思います。特に Subject の場合、このままでは onNext や onError など Observer インタフェースのメソッドが外部から呼べてしまいます。

これを防ぐため、あえて新しい Observable を作って元の Subject の正体(identity)を隠すのがObservable#hide()です。次のようにすると、

class Something {

  private val subject: Subject<Something> = PublishSubject.create()

  fun observeSomething(): Observable<Something> = subject.hide() // hide() で新しい Observable に変換する

}

API を使う側で、受け取った Observable を Subject にキャストできなくなります。

class Client(val something: Something) {

  fun doSomething() {
    val observable = something.observeSomething() // this observable is a new observable created from a subject
    val subject = observable as Subject // ClassCastException!
  }
}

Observable#hide()はもともと、Observable#asObservable()というメソッドでした。これが 2.x へのバージョンアップにおいて名前を変えた、という経緯もあります。