はじめに
KotlinではJavaではできなかった関数を引数に持つ、ということができる。
RxJava系を色々使ってる時にこれを使ってObserverの実装をCoolに書けたので紹介(注:個人の感想です)
えっ、まだObserverのオーバーライド全部書いているんですか!?
まずはこちらのサンプルをkotlinに変換したもの(説明の都合上、一部修正)
fun someMethod() {
val names = arrayOf("Ben", "George")
Observable.from(names).subscribe(object : Observer<String>() {
fun onCompleted() {
}
fun onError(e: Throwable) {
}
fun onNext(s: String) {
println("Hello, $s!")
}
})
}
なんらかのデータをsubscribeして、ObserverのonComplete,onError,onNextをそれぞれオーバーライドしている。
もちろんこれでも問題ないが、実際の実装では大半がonNextだけを実装して、onErrorはせいぜいログ出力、onCompletedに至っては空実装、なんてことはないだろうか。
そしてそんなムダなコードをObserver毎に実装してないだろうか。
それ、関数引数で解決できるよ
で、登場するのが以下の関数
class DefaultObserver<T>(val next:(T)->Unit = {},
val error:(Throwable)->Unit = {},
val completed:()->Unit = {}) : Observer<T>() {
override fun onNext(t: T): Unit = next(t)
override fun onError(e: Throwable): Unit = error(e)
override fun onCompleted(): Unit = completed()
}
最大のポイントはプライマリコンストラクタのnext,error,completedの変数。
これらがそれぞれonNext,onError,onCompletedと同じ型と引数を持つ変数になっているので、onNextらに代入できる。
さらにデフォルト値として空関数をセットしている。これにより実装しなければ何もしない、ということが実現できる。
もちろん、errorのデフォルト引数でログ出力などしても良いだろう。
で、肝心の使うとどうなるか。
fun someMethod() {
val names = arrayOf("Ben", "George")
Observable.from(names).subscribe(DefaultObserver<String>(next = {println("Hello, $it!")}))
}
実装したのは必要最小限のnext = {println("Hello, $it!")}
だけ。使わないonCompletedやonErrorの実装は記載していないのでデフォルトの空実装が呼ばれるようになる。
加えてobject : ~~
といった、情報として意味を持たない実装も消せるところがポイント。
可読性も上がるし、コード量も減るのでかなりオススメです。