"delegates, delegates everywhere" Владимир Миронов

86
Delegates, Delegates everywhere Миронов Владимир

Upload: avitotech

Post on 11-Apr-2017

394 views

Category:

Mobile


7 download

TRANSCRIPT

Page 1: "Delegates, Delegates everywhere" Владимир Миронов

Delegates, Delegates everywhereМиронов Владимир

Page 2: "Delegates, Delegates everywhere" Владимир Миронов

Делегирование

Page 3: "Delegates, Delegates everywhere" Владимир Миронов

Делегирование● Очень часто используемый дизайн паттерн

Page 4: "Delegates, Delegates everywhere" Владимир Миронов

Делегирование● Очень часто используемый дизайн паттерн● Kotlin поддерживает делегирование на уровне языка

Page 5: "Delegates, Delegates everywhere" Владимир Миронов

Делегирование● Очень часто используемый дизайн паттерн● Kotlin поддерживает делегирование на уровне языка● Два вида делегирования в Kotlin

Page 6: "Delegates, Delegates everywhere" Владимир Миронов

Делегирование● Очень часто используемый дизайн паттерн● Kotlin поддерживает делегирование на уровне языка● Два вида делегирования в Kotlin● Interface delegation

Page 7: "Delegates, Delegates everywhere" Владимир Миронов

Делегирование● Очень часто используемый дизайн паттерн● Kotlin поддерживает делегирование на уровне языка● Два вида делегирования в Kotlin● Interface delegation● Property delegation

Page 8: "Delegates, Delegates everywhere" Владимир Миронов

Properties

Page 9: "Delegates, Delegates everywhere" Владимир Миронов

Properties● Понятие field отсутсвует на уровне языка

Page 10: "Delegates, Delegates everywhere" Владимир Миронов

Properties● Понятие field отсутсвует на уровне языка● Есть только property

Page 11: "Delegates, Delegates everywhere" Владимир Миронов

Properties● Понятие field отсутсвует на уровне языка● Есть только property● Пара setter + getter для var и getter для val

Page 12: "Delegates, Delegates everywhere" Владимир Миронов

Properties● Понятие field отсутсвует на уровне языка● Есть только property● Пара setter + getter для var и getter для val● Все обращения происходят через getter и setter

Page 13: "Delegates, Delegates everywhere" Владимир Миронов

Properties● Понятие field отсутсвует на уровне языка● Есть только property● Пара setter + getter для var и getter для val● Все обращения происходят через getter и setter● При необходимости у property есть backing field

Page 14: "Delegates, Delegates everywhere" Владимир Миронов

Property Delegation

Page 15: "Delegates, Delegates everywhere" Владимир Миронов

Property Delegationclass HelloDelegates { var property by Delegate()}

Page 16: "Delegates, Delegates everywhere" Владимир Миронов

Property Delegationclass HelloDelegates { var property by Delegate()}

class HelloDelegates { private val delegate = Delegate()}

Page 17: "Delegates, Delegates everywhere" Владимир Миронов

Property Delegationclass HelloDelegates { var property by Delegate()}

class HelloDelegates { private val delegate = Delegate()

var property: String set(value) = delegate.setValue(this, metadata, value) get() = delegate.getValue(this, metadata)}

Page 18: "Delegates, Delegates everywhere" Владимир Миронов

Property Delegationclass Delegate { operator fun getValue(thisRef: Any, property: KProperty<*>): String operator fun setValue(thisRef: Any, property: KProperty<*>, value: String)}

Page 19: "Delegates, Delegates everywhere" Владимир Миронов

Property Delegationclass Delegate { operator fun getValue(thisRef: Any, property: KProperty<*>): String operator fun setValue(thisRef: Any, property: KProperty<*>, value: String)}

class Delegate : ReadOnlyProperty<Any, String>class Delegate : ReadWriteProperty<Any, String>

Page 20: "Delegates, Delegates everywhere" Владимир Миронов

Built-in delegates● Delegates.notNull()● lazy● Delegates.observable()● Delegates.vetoable

Page 21: "Delegates, Delegates everywhere" Владимир Миронов

Delegates.notNull()class ChatFragment : Fragment() { override fun onAttach(activity: Activity) { super.onAttach(activity) adapter = createMessagesAdapter(context) }}

Page 22: "Delegates, Delegates everywhere" Владимир Миронов

Delegates.notNull()class ChatFragment : Fragment() { private var adapter: MessagesAdapter? = null

override fun onAttach(activity: Activity) { super.onAttach(activity) adapter = createMessagesAdapter(context) }}

Page 23: "Delegates, Delegates everywhere" Владимир Миронов

Delegates.notNull()class ChatFragment : Fragment() { private var adapter: MessagesAdapter? = null

override fun onAttach(activity: Activity) { super.onAttach(activity) adapter = createMessagesAdapter(context) }

private fun onMessagesChanged(messages: List<Message>) { adapter!!.notifyMessagedChanged(messages) }}

Page 24: "Delegates, Delegates everywhere" Владимир Миронов

Delegates.notNull()class ChatFragment : Fragment() { private var adapter: MessagesAdapter by Delegates.notNull()

override fun onAttach(activity: Activity) { super.onAttach(activity) adapter = createMessagesAdapter(context) }

private fun onMessagesChanged(messages: List<Message>) { adapter!!.notifyMessagedChanged(messages) }}

Page 25: "Delegates, Delegates everywhere" Владимир Миронов

Delegates.notNull()class ChatFragment : Fragment() { private var adapter: MessagesAdapter by Delegates.notNull()

override fun onAttach(activity: Activity) { super.onAttach(activity) adapter = createMessagesAdapter(context) }

private fun onMessagesChanged(messages: List<Message>) { adapter.notifyMessagedChanged(messages) }}

Page 26: "Delegates, Delegates everywhere" Владимир Миронов

lazyclass ChatFragment : Fragment() { private val adapter by lazy(LazyThreadSafetyMode.NONE) { createMessagesAdapter(context) }

private fun onMessagesChanged(messages: List<Message>) { adapter.notifyMessagedChanged(messages) }}

Page 27: "Delegates, Delegates everywhere" Владимир Миронов

Delegates.observableclass ChatFragment : Fragment() { private var title by Delegates.observable("Chat") { desc, old, new -> notifyTitleChanged(new) } private fun notifyTitleChanged(title: String) { titleView.text = title }}

Page 28: "Delegates, Delegates everywhere" Владимир Миронов

Наш первый делегатpublic class OvalView extends View { private float radiusX = 100.0f; private float radiusY = 100.0f;}

Page 29: "Delegates, Delegates everywhere" Владимир Миронов

Наш первый делегатpublic class OvalView extends View { private float radiusX = 100.0f; private float radiusY = 100.0f;

public void setRadiusX(float radiusX) { this.radiusX = radiusX; invalidate(); }}

Page 30: "Delegates, Delegates everywhere" Владимир Миронов

Наш первый делегатpublic class OvalView extends View { private float radiusX = 100.0f; private float radiusY = 100.0f;

public void setRadiusX(float radiusX) { this.radiusX = radiusX; invalidate(); }

public void setRadiusY(float radiusY) { this.radiusY = radiusY; invalidate(); }}

Page 31: "Delegates, Delegates everywhere" Владимир Миронов

Наш первый делегатclass OvalView : View() { val radiusX by Delegates.observable(100.0f) { desc, old, new -> invalidate() }

val radiusY by Delegates.observable(100.0f) { desc, old, new -> invalidate() }}

Page 32: "Delegates, Delegates everywhere" Владимир Миронов

Наш первый делегатfun <T> View.bindViewProperty(initial: T): ReadWriteProperty<Any, T> { return Delegates.observable(initial) { desc, old, new -> invalidate() }}

Page 33: "Delegates, Delegates everywhere" Владимир Миронов

Наш первый делегатfun <T> View.bindViewProperty(initial: T): ReadWriteProperty<Any, T> { return Delegates.observable(initial) { desc, old, new -> invalidate() }}

class OvalView : View() { val radiusX by bindViewProperty(100.0f) val radiusY by bindViewProperty(100.0f)}

Page 34: "Delegates, Delegates everywhere" Владимир Миронов

Наш первый делегатfun <T> View.bindViewProperty(initial: T): ReadWriteProperty<Any, T> { return Delegates.observable(initial) { desc, old, new -> invalidate() }}

class OvalView : View() { val radiusX by bindViewProperty(100.0f) val radiusY by bindViewProperty(100.0f)

val centerX by bindViewProperty(50.0f) val centerY by bindViewProperty(50.0f)}

Page 35: "Delegates, Delegates everywhere" Владимир Миронов

Еще один простой делегатfun <V : View> Activity.bindView(id: Int): Lazy<V> { throw UnsupportedOperationException("Implement me!")}

Page 36: "Delegates, Delegates everywhere" Владимир Миронов

Еще один простой делегатfun <V : View> Activity.bindView(id: Int): Lazy<V> { return lazy(LazyThreadSafetyMode.NONE) { findViewById(id) as V }}

Page 37: "Delegates, Delegates everywhere" Владимир Миронов

Еще один простой делегатfun <V : View> Activity.bindView(id: Int): Lazy<V> { return lazy(LazyThreadSafetyMode.NONE) { findViewById(id) as V }}

class UserActivity : Activity() { private val image by bindView<ImageView>(R.id.user_image) private val firstName by bindView<TextView>(R.id.user_first_name) private val lastName by bindView<TextView>(R.id.user_last_name)}

Page 38: "Delegates, Delegates everywhere" Владимир Миронов

Typesafe Bundle Builders

Page 39: "Delegates, Delegates everywhere" Владимир Миронов

Typesafe Bundle Buildersval fragment = UserFragment()val extras = Bundle()

extras.putString("firstName", "Ivan")extras.putString("lastName", "Ivanov")extras.putInt("age", 20)

fragment.arguments = extras

Page 40: "Delegates, Delegates everywhere" Владимир Миронов

Typesafe Bundle Buildersval fragment = UserFragment()val extras = Bundle()

extras.putString("firstName", "Ivan")extras.putString("lastName", "Ivanov")extras.putInt("age", 20)

fragment.arguments = extras

inline fun <reified T : Any> bindArgument(bundle: Bundle, default: T? = null): BundleDelegate { throw UnsupportedOperationException()}

Page 41: "Delegates, Delegates everywhere" Владимир Миронов

Typesafe Bundle Buildersclass UserArguments(val extras: Bundle) { var firstName by bindArgument<String>(extras) var lastName by bindArgument<String>(extras) var age by bindArgument(extras, 33)}

Page 42: "Delegates, Delegates everywhere" Владимир Миронов

Typesafe Bundle Buildersclass UserArguments(val extras: Bundle) { var firstName by bindArgument<String>(extras) var lastName by bindArgument<String>(extras) var age by bindArgument(extras, 33)}

val fragment = UserFragment()val arguments = UserArguments(Bundle())

arguments.firstName = "Ivan"arguments.lastName = "Ivanov"

fragment.arguments = arguments.extras

Page 43: "Delegates, Delegates everywhere" Владимир Миронов

Typesafe Bundle Buildersclass UserFragment : Fragment() { private val args by lazy(LazyThreadSafetyMode.NONE) { UserArguments(arguments) }}

Page 44: "Delegates, Delegates everywhere" Владимир Миронов

LifecycleAware delegatesclass ChatFragment : BaseFragment() { private var chat by Delegates.notNull<ChatModel>() private var messages by Delegates.notNull<CollectionRange<Message>>()}

Page 45: "Delegates, Delegates everywhere" Владимир Миронов

LifecycleAware delegatesclass ChatFragment : BaseFragment() { private var chat by Delegates.notNull<ChatModel>() private var messages by Delegates.notNull<CollectionRange<Message>>()

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) chat = acquireChatModel() messages = chat.acquireMessagesRange() }}

Page 46: "Delegates, Delegates everywhere" Владимир Миронов

LifecycleAware delegatesclass ChatFragment : BaseFragment() { private var chat by Delegates.notNull<ChatModel>() private var messages by Delegates.notNull<CollectionRange<Message>>()

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) chat = acquireChatModel() messages = chat.acquireMessagesRange() }

override fun onDestroy() { messages.close() chat.close() super.onDestroy() }}

Page 47: "Delegates, Delegates everywhere" Владимир Миронов

LifecycleAware delegatesclass ChatFragment : BaseFragment() { private val chat by bindToLifecycleEagerly(LifecycleInterval.CREATED) { acquireChatModel() }

private val participants by bindToLifecycleEagerly(LifecycleInterval.CREATED) { chat.acquireParticipantsRange() }}

Page 48: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass DebugSettings(private val preferences: SharedPreferences) { var logEnabled: Boolean set(value) = preferences.edit().putBoolean("logEnabled", value).apply() get() = preferences.getBoolean("logEnabled", true)

var logTag: String set(value) = preferences.edit().putString("logTag", value).apply() get() = preferences.getString("logTag", "Debug")}

Page 49: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass DebugSettings(private val preferences: SharedPreferences) { var logEnabled by bindPreference(preferences, true) var logTag by bindPreference(preferences, "Debug")}

Page 50: "Delegates, Delegates everywhere" Владимир Миронов

ReadWriteProperty и ReadOnlyProperty

Page 51: "Delegates, Delegates everywhere" Владимир Миронов

ReadWriteProperty и ReadOnlyPropertypublic interface ReadWriteProperty<in R, T> { public operator fun getValue(thisRef: R, property: KProperty<*>): T public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)}

public interface ReadOnlyProperty<in R, out T> { public operator fun getValue(thisRef: R, property: KProperty<*>): T}

Page 52: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T>

Page 53: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T>● Хранит в себе метаинформацию о property

Page 54: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T>● Хранит в себе метаинформацию о property● KProperty<T>.name: String

Page 55: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T>● Хранит в себе метаинформацию о property● KProperty<T>.name: String● KProperty<T>.returnType.javaType: Class

Page 56: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T>● Хранит в себе метаинформацию о property● KProperty<T>.name: String● KProperty<T>.returnType.javaType: Class● KProperty<T>.returnType.isMarkedNullable: Boolean

Page 57: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T>● Хранит в себе метаинформацию о property● KProperty<T>.name: String● KProperty<T>.returnType.javaType: Class● KProperty<T>.returnType.isMarkedNullable: Boolean● KProperty<T>.annotations: List<Annotation>

Page 58: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T> и Android

Page 59: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T> и Android● По дефолту работает только KProperty.name

Page 60: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T> и Android● По дефолту работает только KProperty.name● Оставшимся методам необходима зависимость kotlin-reflect

Page 61: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T> и Android● По дефолту работает только KProperty.name● Оставшимся методам необходима зависимость kotlin-reflect● Количество методов - 12112

Page 62: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T> и Android● По дефолту работает только KProperty.name● Оставшимся методам необходима зависимость kotlin-reflect● Количество методов - 12112● JAR Size - 2268KB

Page 63: "Delegates, Delegates everywhere" Владимир Миронов

KProperty<T> и Android● По дефолту работает только KProperty.name● Оставшимся методам необходима зависимость kotlin-reflect● Количество методов - 12112● JAR Size - 2268KB● DEX size - 1726KB

Page 64: "Delegates, Delegates everywhere" Владимир Миронов

Как жить без reflection

Page 65: "Delegates, Delegates everywhere" Владимир Миронов

Как жить без reflection● KProperty.name работает и так

Page 66: "Delegates, Delegates everywhere" Владимир Миронов

Как жить без reflection● KProperty.name работает и так● KProperty.returnType.javaType - inline reified generic функция

Page 67: "Delegates, Delegates everywhere" Владимир Миронов

Как жить без reflection● KProperty.name работает и так● KProperty.returnType.javaType - inline reified generic функция● KProperty.returnType.isMarkedNullable - два разных делегата

Page 68: "Delegates, Delegates everywhere" Владимир Миронов

Как жить без reflection● KProperty.name работает и так● KProperty.returnType.javaType - inline reified generic функция● KProperty.returnType.isMarkedNullable - два разных делегата

inline fun <reified T : Any> bindValue(): ReadWriteProperty<Any, T> { return createRequiredDelegate(T::class.java)}

Page 69: "Delegates, Delegates everywhere" Владимир Миронов

Как жить без reflection● KProperty.name работает и так● KProperty.returnType.javaType - inline reified generic функция● KProperty.returnType.isMarkedNullable - два разных делегата

inline fun <reified T : Any> bindValue(): ReadWriteProperty<Any, T> { return createRequiredDelegate(T::class.java)}

inline fun <reified T : Any> bindOptionalValue(): ReadWriteProperty<Any, T?> { return createOptionalDelegate(T::class.java)}

Page 70: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass DebugSettings(private val preferences: SharedPreferences) { var logEnabled by bindPreference(preferences, true) var logTag by bindPreference(preferences, "Debug")}

Page 71: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass PreferenceReadWriteProperty<T : Any>( // some arguments here) : ReadWriteProperty<Any, T> { // implement me}

Page 72: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass PreferenceReadWriteProperty<T : Any>( private val preferences: SharedPreferences) : ReadWriteProperty<Any, T> { // implement me}

Page 73: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass PreferenceReadWriteProperty<T : Any>( private val preferences: SharedPreferences, private val clazz: Class<T>) : ReadWriteProperty<Any, T> { // implement me}

Page 74: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass PreferenceReadWriteProperty<T : Any>( private val preferences: SharedPreferences, private val clazz: Class<T>, private val default: T) : ReadWriteProperty<Any, T> { // implement me}

Page 75: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass PreferenceReadWriteProperty<T : Any>( private val preferences: SharedPreferences, private val clazz: Class<T>, private val default: T, private val name: String?) : ReadWriteProperty<Any, T> { // implement me}

Page 76: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { throw UnsupportedOperationException()}

Page 77: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { val key = name ?: property.name}

Page 78: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { val key = name ?: property.name if (!preferences.contains(key)) { return default }}

Page 79: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { val key = name ?: property.name if (!preferences.contains(key)) { return default } return when (clazz) { String::class.java -> preferences.getString(key, null) else -> throw UnsupportedOperationException() } as T}

Page 80: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { val key = name ?: property.name if (!preferences.contains(key)) { return default } return when (clazz) { String::class.java -> preferences.getString(key, null) Int::class.java -> preferences.getInt(key, 0) else -> throw UnsupportedOperationException() } as T}

Page 81: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { val key = name ?: property.name if (!preferences.contains(key)) { return default } return when (clazz) { String::class.java -> preferences.getString(key, null) Int::class.java -> preferences.getInt(key, 0) Long::class.java -> preferences.getLong(key, 0L) else -> throw UnsupportedOperationException() } as T}

Page 82: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { val key = name ?: property.name if (!preferences.contains(key)) { return default } return when (clazz) { String::class.java -> preferences.getString(key, null) Int::class.java -> preferences.getInt(key, 0) Long::class.java -> preferences.getLong(key, 0L) Boolean::class.java -> preferences.getBoolean(key, false) else -> throw UnsupportedOperationException() } as T}

Page 83: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesoverride fun getValue(thisRef: Any, property: KProperty<*>): T { val key = name ?: property.name if (!preferences.contains(key)) { return default } return when (clazz) { String::class.java -> preferences.getString(key, null) Int::class.java -> preferences.getInt(key, 0) Long::class.java -> preferences.getLong(key, 0L) Boolean::class.java -> preferences.getBoolean(key, false) Float::class.java -> preferences.getFloat(key, 0.0f) else -> throw UnsupportedOperationException() } as T}

Page 84: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesinline fun <reified T : Any> bindPreference( preferences: SharedPreferences, default: T, name: String? = null) : ReadWriteProperty<Any, T> { return PreferenceReadWriteProperty(preferences, T::class.java, default, name)}

Page 85: "Delegates, Delegates everywhere" Владимир Миронов

Preferences delegatesclass DebugSettings(private val preferences: SharedPreferences) { var logEnabled by bindPreference(preferences, true) var logTag by bindPreference(preferences, "Debug")}