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

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

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

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

Avatar for pluulove (노현석)

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 ٣੗ੋ ಁఢ