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

Kotlin을 여행하는 히치하이커의 준비서

Kotlin을 여행하는 히치하이커의 준비서

Kotlin/Everywhere Seoul 2019 에서 발표한 자료입니다.

pluulove (노현석)

August 26, 2019
Tweet

More Decks by pluulove (노현석)

Other Decks in Technology

Transcript

  1. Pluu Dev. ࣁ࣌ਸ ా೧ࢲ ঳ਸ ࣻ ੓ח Ѫ - "by"

    ఃਕ٘ী ؀ೠ ੄޷ - Kotlinীࢲ ੽Ӕೞח Delegation - ׮द ೠߣ Delegation ୓௼ - ࢚ࣘী ؀ೠ ऀ਷ য়ܨ ҕਬ
  2. Pluu Dev. Property Accessor Setter Getter Field Effective Java #15

    ௿ېझ৬ ݯߡ੄ ੽Ӕ ӂೠਸ ୭ࣗചೞۄ
  3. Pluu Dev. Property Accessor Setter Getter Field Effective Java #15

    ௿ېझ৬ ݯߡ੄ ੽Ӕ ӂೠਸ ୭ࣗചೞۄ
  4. Pluu Dev. ఃਕ٘۽ ࠄ "by" • Interface ҳഅਸ ׮ܲ ё୓ী

    ਤ੐ • Property੄ Accessor ҳഅਸ ׮ܲ ё୓ী ਤ੐ Reference : https://kotlinlang.org/docs/reference/keyword-reference.html
  5. Pluu Dev. ఃਕ٘۽ ࠄ "by" • Interface ҳഅਸ ׮ܲ ё୓ী

    ਤ੐ • Property੄ Accessor ҳഅਸ ׮ܲ ё୓ী ਤ੐ Reference : https://kotlinlang.org/docs/reference/keyword-reference.html Interface ҳഅਸ ׮ܲ ё୓ী ਤ੐ Property੄ Accessor ҳഅਸ ׮ܲ ё୓ী ਤ੐
  6. Pluu Dev. Hard/Soft Keyword val else = 5 // Hard

    Keyword println(else) val by = 10 // Soft Keyword println(by) Compile Error // 10 // Example fun testSo*Keyword(by: Int) { println(by) }
  7. Prototypical Objects ੽Ӕ ߑध਷ ӝࠄ ૑धਸ ಴അೞҊ ѐ֛ਸ ز੸ਵ۽ ࣻ੿ೞח

    ؘ ੓য ݻ о૑ ੢੼੉ ੓णפ׮. ਤ੐਷ ੉ܳ ё୓ ૑ೱ ঱য۽ ҳഅೞӝਤೠ ݫழפ્ੑפ׮. Using Prototypical Objects to Implement Shared Behavior in Object Oriented Systems by Henry Lieberman Pluu Dev.
  8. Pluu Dev. Delegation Pattern ࣗ೐౟ਝয ূ૑פয݂ীࢲ ਤ੐ ಁఢ਷ ё୓ ҳࢿীࢲ

    ࢚ࣘҗ زੌೠ ௏٘ ੤ࢎਊਸ ׳ࢿೡ ࣻ ੓ب۾ೞח ё୓ ૑ೱ ٣੗ੋ ಁఢ Reference : https://en.wikipedia.org/wiki/Delegation_pattern
  9. Pluu Dev. Simple Delegation Pattern class Rectangle(val width: Int, val

    height: Int) { fun area() = width * height } class Window(val bounds: Rectangle) { // Delegation fun area() = bounds.area() } Reference : https://en.wikipedia.org/wiki/Delegation_pattern
  10. Pluu Dev. Properties Delegate class Example { var p: String

    by Delegate() } val/var <property name>: <Type> by <expression> Reference : https://kotlinlang.org/docs/reference/delegated-properties.html
  11. Pluu Dev. Properties Delegate import kotlin.reflect.KProperty class Delegate { operator

    fun getValue(thisRef: Any?, property: KProperty<*>): String { // Property Get ੽Ӕद ഐ୹ } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { // Property Set ੽Ӕद ഐ୹ } } Reference : https://kotlinlang.org/docs/reference/delegated-properties.html Reference : https://kotlinlang.org/docs/reference/operator-overloading.html
  12. Pluu Dev. Properties Delegate class Example { var p: String

    by Delegate() } val example = Example() println(example.p) example.p = “A” delegate.getValue ഐ୹ delegate.setValue ഐ୹
  13. Pluu Dev. Lazy val lazyValue: String by lazy { "Hello"

    } fun main() { println(lazyValue) println(lazyValue) } property ഐ୹੹ө૑ Instance ࢤࢿਸ ૑ো Ӓ ੉റח நदػ Instanceী ੽Ӕ
  14. Pluu Dev. Lazy val lazyValue: String by lazy { "Hello"

    } झۨ٘۽ࠗఠ উ੹? زदࢿ ೲਊ?
  15. Pluu Dev. LazyThreadSafetyMode public actual fun <T> lazy( mode: LazyThreadSafetyMode,

    initializer: () -> T ): Lazy<T> = when (mode) { LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) } Reference : https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jvm/src/kotlin/util/LazyJVM.kt#L33 public actual fun <T> lazy( initializer: () -> T ): Lazy<T> = SynchronizedLazyImpl(initializer)
  16. Pluu Dev. Kotlin stdlibীࢲ੄ Delegate Interface interface ReadOnlyProperty<in R, out

    T> { operator fun getValue(thisRef: R, property: KProperty<*>): T } interface ReadWriteProperty<in R, T> { operator fun getValue(thisRef: R, property: KProperty<*>): T operator fun setValue(thisRef: R, property: KProperty<*>, value: T) } Reference : https://kotlinlang.org/docs/reference/delegated-properties.html#property-delegate-requirements
  17. Pluu Dev. Delegates.vetoable public inline fun <T> vetoable( initialValue: T,

    crossinline onChange: ( property: KProperty<*>, oldValue: T, newValue: T ) -> Boolean): ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) { override fun beforeChange( property: KProperty<*>, oldValue: T, newValue: T ): Boolean = onChange(property, oldValue, newValue) }
  18. Pluu Dev. Delegates.vetoable class User { var name: String by

    Delegates.vetoable("initialValue") { _, _, new -> new.length > 5 } } fun main() { val user = User() user.name = "first" user.name = "second" println(user.name) } initialValue
  19. Pluu Dev. Delegates.vetoable class User { var name: String by

    Delegates.vetoable("initialValue") { _, _, new -> new.length > 5 } } fun main() { val user = User() user.name = "first" user.name = "second" println(user.name) } ч ߸҃ ৈࠗܳ ౸ױೞח ௒ߔ
  20. Pluu Dev. Delegates.observable public inline fun <T> observable( initialValue: T,

    crossinline onChange: ( property: KProperty<*>, oldValue: T, newValue: T ) -> Unit ): ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) { override fun afterChange( property: KProperty<*>, oldValue: T, newValue: T ) = onChange(property, oldValue, newValue) }
  21. Pluu Dev. Delegates.observable class User { var name: String by

    Delegates.observable("initialValue") { _, old, new -> println("$old -> $new") } } fun main() { val user = User() user.name = "first" user.name = "second" } Reference : https://kotlinlang.org/docs/reference/delegated-properties.html#observable initialValue
  22. Pluu Dev. Delegates.observable class User { var name: String by

    Delegates.observable("initialValue") { _, old, new -> println("$old -> $new") } } fun main() { val user = User() user.name = "first" user.name = "second" } Reference : https://kotlinlang.org/docs/reference/delegated-properties.html#observable ч ߸҃ റ ഐ୹غח ௒ߔ
  23. Pluu Dev. public abstract class ObservableProperty<T>( initialValue: T) : ReadWriteProperty<Any?,

    T> { private var value = initialValue protected open fun beforeChange( property: KProperty<*>, oldValue: T, newValue: T): Boolean = true protected open fun afterChange( property: KProperty<*>, oldValue: T, newValue: T): Unit {} ... } ObservableProperty
  24. Pluu Dev. public abstract class ObservableProperty<T>( initialValue: T) : ReadWriteProperty<Any?,

    T> { private var value = initialValue protected open fun beforeChange( property: KProperty<*>, oldValue: T, newValue: T): Boolean = true protected open fun afterChange( property: KProperty<*>, oldValue: T, newValue: T): Unit {} ... } /** Delegates.vetoableীࢲ overrideೞח ೣࣻ */ ObservableProperty
  25. Pluu Dev. public abstract class ObservableProperty<T>( initialValue: T) : ReadWriteProperty<Any?,

    T> { private var value = initialValue protected open fun beforeChange( property: KProperty<*>, oldValue: T, newValue: T): Boolean = true protected open fun afterChange( property: KProperty<*>, oldValue: T, newValue: T): Unit {} ... } /** Delegates.observableীࢲ overrideೞח ೣࣻ */ ObservableProperty
  26. Pluu Dev. Class Delegation interface A { fun blabla() fun

    blabla2() } class AImpl : A { override fun blabla() { println("Hello delegation!") } override fun blabla2() { println("blabla2 delegation!") } } class B(a: A) : A by a ೙ਃೠ ࠗ࠙݅ ੤੿੄ class C(private val a: A) : A by a { override fun blabla() { println("Override method!") } } class D : A by AImpl()
  27. Pluu Dev. Local Delegated Properties (Since 1.1) ૑৉߸ࣻ ࢤࢿਸ ૑ো୊ܻ

    fun example(computeFoo: () -> Foo) { val memoizedFoo by lazy(computeFoo) if (someCondition && memoizedFoo.isValid()) { memoizedFoo.doSomething() } } Reference : https://kotlinlang.org/docs/reference/delegated-properties.html#local-delegated-properties-since-11
  28. Pluu Dev. Local Delegated Properties (Since 1.1) ૑৉߸ࣻ ࢤࢿਸ ૑ো୊ܻ

    fun testLocalDelegation() { val database by lazy { createDatabase() } val cache by lazy { createMemoryCache() } if (mustUseDatabase()) { database.use { ... } } else { cache.use { ... } } } Reference : https://blog.jetbrains.com/kotlin/2017/04/kotlin-1-1-is-also-for-android-developers/ ૑ো ୡӝച۽ db/cache ઺ ೞա ࢎਊ
  29. Pluu Dev. Providing a delegate (Since 1.1) class SharedPreferencesProperty( private

    val key: String, private val defaultValue: String? ) : ReadWriteProperty<PreferencesModel, String?> { override fun getValue(thisRef: PreferencesModel, property: KProperty<*> ): String? { return thisRef.sharedPreferences.getString(key, defaultValue) } override fun setValue( thisRef: PreferencesModel, property: KProperty<*>, value: String? ) { thisRef.sharedPreferences.edit().putString(key, value).apply() } }
  30. Pluu Dev. Providing a delegate (Since 1.1) class SharedPreferencesPropertyProvider( private

    val key: String? = null, private val defaultValue: String? = null ) { operator fun provideDelegate( thisRef: PreferencesModel, prop: KProperty<*> ): ReadWriteProperty<PreferencesModel, String?> { val propertyName = prop.name val key = key ?: propertyName require(key.isNotEmpty()) { "Key cannot be empty" } return SharedPreferencesProperty(key, defaultValue) } }
  31. Pluu Dev. Providing a delegate (Since 1.1) open class PreferencesModel(context:

    Context, name: String) { internal val sharedPreferences: SharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE) protected fun stringPreferences( key: String? = null, defaultValue: String? = null ) = SharedPreferencesPropertyProvider(key, defaultValue) }
  32. Pluu Dev. Providing a delegate (Since 1.1) open class PreferencesModel(context:

    Context, name: String) { internal val sharedPreferences: SharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE) protected fun stringPreferences( key: String? = null, defaultValue: String? = null ) = SharedPreferencesPropertyProvider(key, defaultValue) } class UserPreferences( context: Context ) : PreferencesModel(context, "user") { var name: String? by stringPreferences() var profile: String? by stringPreferences("profile") }
  33. Pluu Dev. Providing a delegate (Since 1.1) PreferencesModel # stringPreferences(key:

    String?, defaultValue: String?)
 : SharedPreferencesPropertyProvider UserPreferences + name: String? by stringPreferences + profile: String? by stringPreferences Providing a delegate (Since 1.1) SharedPreferencesPropertyProvider - key: String? - val defaultValue: String? + provideDelegate(thisRef: PreferencesModel, prop: KProperty<*>)
 : ReadWriteProperty<PreferencesModel, String?> SharedPreferencesProperty - key: String? - val defaultValue: String? + getValue(thisRef: PreferencesModel, property: KProperty<*>): String? + setValue(thisRef: PreferencesModel, property: KProperty<*>, value: String?)
  34. Pluu Dev. bind/extra ৘द fun Activity.bindString(@StringRes resId: Int): Lazy<String> =

    lazy { getString(resId) } fun Activity.bindColor(@ColorRes resId: Int): Lazy<Int> = lazy { ContextCompat.getColor(this, resId) } fun <T : Parcelable> Activity.extra(key: String): Lazy<T> = lazy { intent.extras?.getParcelable<T>(key)!! } fun Activity.extraString(key: String): Lazy<String> = lazy { intent.getStringExtra(key) }
  35. Pluu Dev. bind/extra ৘द fun Activity.bindString(@StringRes resId: Int): Lazy<String> =

    lazy { getString(resId) } fun Activity.bindColor(@ColorRes resId: Int): Lazy<Int> = lazy { ContextCompat.getColor(this, resId) } fun <T : Parcelable> Activity.extra(key: String): Lazy<T> = lazy { intent.extras?.getParcelable<T>(key)!! } fun Activity.extraString(key: String): Lazy<String> = lazy { intent.getStringExtra(key) } class TestActivity : Activity() { private val title by bindString(R.string.title) private val accentColor by bindColor(R.color.color_accent) private val param by extra<Param>(KEY_PARAM) private val keyword by extraString(KEY_KEYWORD) }
  36. Pluu Dev. Preference ৘द class IntPreference( private val preferences: SharedPreferences,

    private val name: String, private val defaultValue: Int = 0 ) : ReadWriteProperty<Any, Int> { override fun getValue(thisRef: Any, property: KProperty<*>): Int { return preferences.getInt(name, defaultValue) } override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) { preferences.edit().putInt(name, value).apply() } }
  37. Pluu Dev. Preference ৘द class IntPreference( private val preferences: SharedPreferences,

    private val name: String, private val defaultValue: Int = 0 ) : ReadWriteProperty<Any, Int> { override fun getValue(thisRef: Any, property: KProperty<*>): Int { return preferences.getInt(name, defaultValue) } override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) { preferences.edit().putInt(name, value).apply() } } class Test(private val pref: SharedPreferences) { val count: Int by IntPreference(pref, "count", 0) }
  38. Pluu Dev. BaseObservable ഝਊ class UserModel(private val user: UserData) :

    BaseObservable() { @get:Bindable var name: String = "" get() = user.name set(value) { user.name = value notifyPropertyChanged(BR.name) } }
  39. Pluu Dev. ObservablePropertyDelegate class ObservablePropertyDelegate<T> ( data: T, id: Int

    ) : ReadWriteProperty<Any?, T> { override fun getValue(thisRef: Any?, property: KProperty<*>): T { return data } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { data = value notifyPropertyChanged(id) } }
  40. Pluu Dev. Delegation ੸ਊ ੹ class UserModel(private val user: UserData)

    : BaseObservable() { @get:Bindable var name: String = "" get() = user.name set(value) { user.name = value notifyPropertyChanged(BR.name) } }
  41. Pluu Dev. Delegation ੸ਊ റ class UserModel(private val user: UserData)

    : BaseObservable() { @get:Bindable var name: String by ObservablePropertyDelegate(user.name, BR.name) }
  42. Pluu Dev. fun mainTest() { val b = BaseImpl(100) b.printX()

    QuizType1(b, 30).printX() QuizType2(b, 30).printX() } interface Quiz1Base { val x: Int fun printX() { println(x) } } class BaseImpl( override val x: Int ) : Quiz1Base class QuizType1( b: Quiz1Base, override val x: Int ) : Quiz1Base by b class QuizType2( b: Quiz1Base, override val x: Int ) : Quiz1Base ? ? ?
  43. Pluu Dev. interface Quiz1Base { val x: Int fun printX()

    { println(x) } } class BaseImpl( override val x: Int ) : Quiz1Base class QuizType1( b: Quiz1Base, override val x: Int ) : Quiz1Base by b class QuizType2( b: Quiz1Base, override val x: Int ) : Quiz1Base fun mainTest() { val b = BaseImpl(100) b.printX() QuizType1(b, 30).printX() QuizType2(b, 30).printX() } 100 100 30
  44. Pluu Dev. fun mainTest() { val b = BaseImpl(100) b.printX()

    // 100 QuizType1(b, 30).printX() // 100 QuizType2(b, 30).printX() // 30 } QuizType1 (30) printX() QuizType2 (30) printX() <<interface>> Quiz1Base x: Int printX(): Unit BaseImpl (100) printX()
  45. Pluu Dev. class Quiz2HashSet<E> : HashSet<E>() { var addCount: Int

    = 0 private set override fun add( element: E ): Boolean { addCount++ return super.add(element) } override fun addAll( elements: Collection<E> ) : Boolean { addCount += elements.size return super.addAll(elements) } ... } val set = Quiz2HashSet<Int>() set.add(1) set.add(2) println(set.addCount) set.addAll(setOf(3, 4, 5)) println(set.addCount) ? ?
  46. Pluu Dev. val set = Quiz2HashSet<Int>() set.add(1) set.add(2) println(set.addCount) set.addAll(setOf(3,

    4, 5)) println(set.addCount) 2 8 class Quiz2HashSet<E> : HashSet<E>() { var addCount: Int = 0 private set override fun add( element: E ): Boolean { addCount++ return super.add(element) } override fun addAll( elements: Collection<E> ) : Boolean { addCount += elements.size return super.addAll(elements) } ... }
  47. Pluu Dev. • HashSet#addAll਷ AbstractCollection#addAllਸ ഐ୹ • addAll() ղࠗীࢲ addਸ

    ഐ୹ೣ java.lang.Object ⽸ java.util.AbstractCollection<E> ⽸ java.util.AbstractSet<E> ⽸ java.util.HashSet<E> class Quiz2HashSet<E> : HashSet<E>() { var addCount: Int = 0 private set override fun add( element: E ): Boolean { addCount++ return super.add(element) } override fun addAll( elements: Collection<E> ) : Boolean { addCount += elements.size return super.addAll(elements) } ... }
  48. Pluu Dev. Kotlin in Action 4.3.3 ௿ېझ ਤ੐: by ఃਕ٘

    ࢎਊ Effective Java ই੉మ 18 ࢚ࣘࠁ׮ח ஹನ૑࣌ਸ ࢎਊೞۄ
  49. Pluu Dev. class Quiz2HashSet<E> : HashSet<E>() { var addCount: Int

    = 0 private set override fun add(element: E): Boolean { addCount++ return super.add(element) } override fun addAll(elements: Collection<E>) : Boolean { addCount += elements.size return super.addAll(elements) } ... }
  50. Pluu Dev. class Quiz2HashSet<E>( private val set: MutableSet<E> = mutableSetOf()

    ) : MutableSet<E> by set { var addCount: Int = 0 private set override fun add(element: E): Boolean { addCount++ return set.add(element) } override fun addAll(elements: Collection<E>): Boolean { addCount += elements.size return set.addAll(elements) } … } Class Delegation
 ਤ੐ ഋక۽ ҳഅ
  51. Pluu Dev. Delegation ੢ױ੼ • ࢚ࣘ਷ ױ ೞա੄ Super Class݅

    оמ,
 ਤ੐਷ ࠂࣻ Interface۽ оמ • بݫੋ ૑धਸ Delegationਵ۽ ऀӡ ࣻ ੓׮. • ࢚ࣘ਷ ё୓ ௼ӝо ૐоदఃח ࠺ਊ੉ ߊࢤ • Interface ੿੄о ೙ਃ • ਬোೞ૑݅ ੉೧ೞӝ য۵׮ • protected method/propertiesח ࢎਊ ࠛоמ
  52. Pluu Dev. https://github.com/google/guava/blob/master/guava/src/com/google/common/collect/ForwardingCollection.java - Child Classח Super Class੄ ҳഅ ࣁࠗ

    ࢎ೦ী ੄ઓ
 ➤ ࢚ࣘ੉ ஭ङചܳ ӵ౟ܽ׮. [Snyder86] - ࢚ࣘ਷ ࠗݽ/੗ध੉ ࣽࣻೠ is-a ҙ҅ੌ ٸ ࢎਊ - ࢚ࣘ਷ API੄ ߧਤ৬ Ѿೣਸ ࢚ࣘؼ ࣻ ੓׮ - Decorator Pattern ਸ ੉ਊ೧ࢲ ҳഅী ૘઺ೞח ੽Ӕ
 ➤ Wrapper Class : Guava ForwardingCollection Effective Java #16 ࢚ࣘࠁ׮ח ஹನ૑࣌ਸ ࢎਊೞۄ
  53. Pluu Dev. Reference • Kotlin Reference ~ Delegated Properties •

    [Blog] بହ਌ש੄ ನझ౟ ⭑⭑⭑⭑⭑ • https://medium.com/til-kotlin-ko/kotlin੄-௿ېझ-ਤ੐਷-যڌѱ-ز੘ೞחо- c14dcbbb08ad • https://medium.com/til-kotlin-ko/kotlin-delegated-property-by-lazyח-যڌѱ-ز ੘ೞחо-74912d3e9c56 • [Blog] Using Prototypical Objects to Implement Shared Behavior in Object Oriented Systems by Henry Lieberman • [Blog] Kotlin “By” Class Delegation: Favor Composition Over Inheritance • [Book] Effective Java • [Book] GoF ٣੗ੋ ಁఢ