Types of Delegation
- Explicit Delegation: All object-oriented languages support it, and it is accomplished by giving a delegate (the one to be implemented) object to the delegating object (the one that will implement the delegate object).
- Implicit Delegation: The delegation pattern needs language-level support.
Overriding a delegation-implemented interface member
Overrides function as expected: the compiler will utilize your override implementations rather than those in the delegate object. If you add the override fun put() print("Hello") to DerivedClass when put is called, the program will print Hello instead of CodingNinjas:
Code:
interface BaseInterface {
fun put()
}
class BaseClass(private val name: String) : BaseInterface {
override fun put() {
println(name)
}
}
class DerivedClass(baseInterface: BaseInterface) : BaseInterface by baseInterface {
// overriding member of interface method
override fun put() {
println("Hello")
}
}
fun main() {
val baseClass = BaseClass("Coding Ninjas")
DerivedClass(baseClass).put() // it will call override method of DerivedClass
baseClass.put() // to call BaseClass method we have to use this
}
Output:
Hello
Coding Ninjas
However, it should be noted that elements overwritten in this manner are not called from the delegate object's members, which can only access its implementations of the interface members.
Code:
interface BaseInterface {
val no: Int
fun put()
}
class BaseClass(private val name: String) : BaseInterface {
override val no: Int = 2017
override fun put() {
println(name)
}
}
class DerivedClass(baseInterface: BaseInterface) : BaseInterface by baseInterface {
// the property is not accessible from baseInterface implementation of put
override val no = 17
}
fun main() {
val baseClass = BaseClass("Coding Ninjas")
val derivedClass = DerivedClass(baseClass)
derivedClass.put()
println(derivedClass.no)
}
Output:
Coding Ninjas
17
We get no variable value as 2017 only from baseClass object and not from derivedClass object.
Property Delegation
Delegation is the process of shifting responsibility to another class or method. When a property has been declared in several locations, we should use the same code to initialize it. Here we will use methods that Kotlin Library provides.
Using Lazy()
Lazy is a lambda function that accepts a property as an input and returns an instance of Lazy<T>, where <T> is the type of the properties it uses.
If you want to know more about Lambda Expressions, please reach out to this article for further information.
Code:
val name: String by lazy {
"Coding Ninjas"
}
fun main() {
println("$name has the best content")
}
Output:
Coding Ninjas has the best content
We send a variable name to the Lazy function, which assigns the value to its object and returns it to the main() function.
Delegation.Observable()
Observable() accepts two arguments to initialize the object and returns the same to the calling function.
Code:
import kotlin.properties.Delegates
class Student {
var name: String by Delegates.observable("Kurenai") { property, oldName, newName ->
println("$oldName -> $newName")
}
}
fun main() {
val student = Student()
student.name = "Sensei"
student.name = "CodingNinjas"
}
Output:
Kurenai -> Sensei
Sensei -> CodingNinjas
Observable()'s first argument is the initial value of the property. The second argument is the callback function that will print oldName and newName. This will be called when we change the specified property's value.
Application of Delegation
Let's have a look at some everyday use cases for the delegation pattern now.
First, we can utilize the delegation pattern to use existing implementations to implement various interfaces.
Syntax:
class BaseClass : InterfaceOne by Interface1(), InterfaceTwo by Interface2()
Second, delegation can be used to improve an existing implementation. We have already covered this in the overriding delegation implemented method.
Lastly, It is a versatile, powerful, and mutable method.
Check out this article - Compile Time Polymorphism
Conclusion
Now, keep in mind that the delegate does not know the decorator. Finally, it's worth noting that with Kotlin, we can delegate not just to interfaces but also to single properties.
FAQs
-
Why is delegation better than inheritance?
The main benefit of delegation is runtime flexibility. At runtime, the delegate can be readily modified. However, unlike inheritance, most popular object-oriented languages may not directly enable delegation, and it does not allow for dynamic polymorphism.
-
Does delegation promote code reuse?
Delegation is a technique that encourages code reuse by allowing runtime function activation in the context of a given instance - regardless of the instance and function's hierarchical history.
-
What's the difference between lazy and Lateinit?
Lateinit can only be used with var properties, whereas lazy is always used with val properties. A lateinit property can be reinitialized as needed, whereas a lazy property can only be initialized once.
Key Takeaways
Cheers if you reached here!!
The purpose of this article was to introduce you to the Kotlin Delegation, its various types, application, override methods, and understand the basic core concept about Delegation in Android Development.
If you want to learn more about Reflection in Kotlin, you can jump to this article which covers them in great detail.
However, learning never stops, and there is more to learn. So head over to our Android Development Course on the Coding Ninjas Website to dive deep into Android Development and build future applications. Till then, Happy Learning!