Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Immutable data holder

Avatar for haru067 haru067
February 28, 2019

Immutable data holder

Avatar for haru067

haru067

February 28, 2019
Tweet

More Decks by haru067

Other Decks in Technology

Transcript

  1. MVVMによる実装 • ユーザIDを引数としてViewModelがRepository からfetch • pro leはDataBindingを通じてViewに表示 fun load(userId: String)

    = profileRepository.fetchProfile(userId) { profile.value = it } ProfileViewModel.kt var profile = MutableLiveData<Profile>()
  2. MVVMによる実装 • ユーザIDを引数としてViewModelがRepository からfetch • pro leはDataBindingを通じてViewに表示 fun load(userId: String)

    = profileRepository.fetchProfile(userId) { profile.value = it } ProfileViewModel.kt var profile = MutableLiveData<Profile>()
  3. MVVMによる実装 • ユーザIDを引数としてViewModelがRepository からfetch • pro leはDataBindingを通じてViewに表示 fun load(userId: String)

    = profileRepository.fetchProfile(userId) { profile.value = it } ProfileViewModel.kt var profile = MutableLiveData<Profile>() ͳΜͱ͔͠ͳ͍ͱɾɾɾɾ
  4. Lv1: mutableな変数宣言をやめる 知らないうちにobserveできなくなってしまう val に書き換えでimmutableに var data = MutableLiveData<String>() data.observe(this,

    Observer { print(it) }) data.value = "hello" data = MutableLiveData() data.value = "world" // ͜͜͸observe͞Εͳ͍ var profile = MutableLiveData<Profile>() val profile = MutableLiveData<Profile>()
  5. Lv2: mutableなデータを公開しない 変数をvalにしてもオブジェクト自体はまだmutable   ViewがViewModelのデータを変更できてしまう
 外からはread onlyなデータだけが見える形にする val data =

    MutableLiveData<String>() data.value = "hello" data.value = "world" // いくらでも更新できる private val _profile: MutableLiveData<Profile>() val profile: LiveData<Profile> get() = _profile val profile = MutableLiveData<Profile>()
  6. 良さそう? まあよさそう。だが、、
 
 
 
 
 privateとはいえViewModel内なら書き換え可能 • ViewModelが肥大化したら多分事故る •

    そもそも2つも変数を宣言するのはくどい private val _profile: MutableLiveData<Profile>() val profile: LiveData<Profile> get() = _profile ProfileViewModel.kt
  7. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) }
  8. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) } userIdの変更を監視
  9. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) } IDに変更があればfetch
  10. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) }
  11. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
 • 「pro leはIDの更新以外を理由に変更できない」
 という制約をコード上で表現することができる • 「pro

    leはIDをトリガーとしてfetchした値」
 というデータのフローが明確になる private val _userId = MutableLiveData<String>() … val profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) }
  12. Bonus: より簡潔に 拡張関数を活用すると良さそう(ktxにある?)
 
 
 Transformations.switchMap(_userId) { profileRepository.getProfile(it) } _userId.switchMap

    { profileRepository.getProfile(it) } fun <X, Y> LiveData<X>.switchMap(body: (X) -> LiveData<Y>): 
 LiveData<Y> { return Transformations.switchMap(this, body) } 長い シンプル https://github.com/google/iosched ͷ Extensions.kt ΑΓ