Kotlinタイプのセキュリティビルダーの一回の運用履歴


Android公式指導の関連アプリケーションの枠組みにおいて、Resourceクラスを用いて、ネットワーク要求の状態と結果を表します。

// A generic class that contains data and status about loading this data.
sealed class Resource<T>(
 val data: T? = null,
 val message: String? = null
) {
 class Success<T>(data: T) : Resource<T>(data)
 class Loading<T>(data: T? = null) : Resource<T>(data)
 class Error<T>(message: String, data: T? = null) : Resource<T>(data, message)
}
ほとんどの場合、私たちはactivityの中でこのように使います。

private val testViewModel : TestViewModel by viewModels()

private fun getUserInfo(uid: String) {
 testViewModel.userInfoData.observe(this, Observer {
  when (it.status) {
   Status.SUCCESS -> TODO()
   Status.ERROR -> TODO()
   Status.LOADING -> TODO()
  }
 })
 testViewModel.setUserId(uid)
}
このように書くのが多くなりました。面倒くさいです。毎回whenです。もっとさわやかな書き方がありますか?例えばこうですか?

private fun getUserInfo(uid: String) {
 testViewModel.userInfoData.observe(this, Observer {
  success {
   
  }
  error {
   
  }
  loading {
   
  }
 })
 testViewModel.setUserId(uid)
}
successだけを処理したい時は、error/loadingの状況を書かなくてもいいです。
kotlinのタイプのセキュリティビルダーができます。まず公式の例を見てみます。

class HTML {
 fun body() { …… }
}

fun html(init: HTML.() -> Unit): HTML {
 val html = HTML() //        
 html.init()  //            lambda
 return html
}

html {  //       lambda     
 body() //              
}
まず分析してみます。Observerインターフェースを実現したオブジェクトが必要です。
ですから、まず一つのクラスを定義してObserverインターフェースを実現します。

class ResourceObserver<T: Any> : Observer<Resource<T>> {
 override fun onChanged(t: Resource<T>) {
  when(t) {
   is Resource.Success -> TODO()
   is Resource.Error -> TODO()
   is Resource.Loading -> TODO()
  }
 }
}
トップレベルの関数を実行して、Resource Observerオブジェクトを返します。

fun <T: Any> resourceObserver(init: ResourceObserver<T>.() -> Unit): ResourceObserver<T> {
 val observer = ResourceObserver<T>()
 observer.init()
 return observer 
}
この関数を呼び出すと、Resource Observerオブジェクトが得られます。

resourceObserver {
 //               
}
だから私の実現は

class ResourceObserver<T: Any> : Observer<Resource<T>> {
 private var success: (Resource.Success<T>.() -> Unit)? = null
 private var error: (Resource.Error.() -> Unit)? = null
 private var loading: (Resource.Loading<T>.() -> Unit)? = null
 
 fun success(s: (Resource.Success<T>.() -> Unit)) {
  success = s
 }
 
 fun error(e: Resource.Error.() -> Unit) {
  error = e
 }
 
 fun loading(l: Resource.Loading<T>.() -> Unit) {
  loading = l
 }
 
 override fun onChanged(t: Resource<T>) {
  when(t) {
   is Resource.Success -> success?.invoke(t)
   is Resource.Error -> error?.invoke(t)
   is Resource.Loading -> loading?.invoke(t)
  }
 }
}
締め括りをつける
ここでKotlinタイプのセキュリティビルダーの運用履歴に関する記事を紹介します。Kotlinタイプのセキュリティビルダーの運用内容については、以前の文章を検索したり、下記の関連記事を見たりしてください。これからもよろしくお願いします。