Kotlin Delegation: Clean Code Pattern
Table of Contents
🤝 Composition over Inheritance
Inheritance is often abused in OOP. It creates tight coupling. The Delegation pattern solves this by favoring composition. Kotlin makes this a first-class citizen with the by keyword.
The Problem
You want to extend the functionality of a class (e.g., ArrayList), but you can’t or shouldn’t inherit from it directly because you only need to override one method and delegate the rest.
The Solution: Class Delegation
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}
The compiler generates all the forwarding methods for Base interface automatically. Zero boilerplate.
📦 Property Delegation
The most common use case in Android.
by lazy
Delays initialization until the first access. Thread-safe by default.
val heavyObject: Heavy by lazy {
Heavy() // Computed only once
}
by viewModels()
In Android KTX, we delegate ViewModel creation to a factory.
val viewModel: UserViewModel by viewModels()
by remember (Compose)
Not technically a property delegate in the language sense, but conceptually similar. It delegates state retention to the composition.
🛠️ Custom Delegates
You can write your own!
class SharedPrefDelegate(context: Context, key: String, default: String) {
// operator getValue / setValue
}
var username by SharedPrefDelegate(context, "user_name", "Guest")
Now, username = "Alex" writes to SharedPreferences automatically.
⚠️ When NOT to Use It
- Performance: While negligible, there is a tiny overhead for property delegation (object allocation).
- Readability: Don’t hide complex logic in custom delegates. If a variable assignment triggers a network call, it’s confusing.
🏁 Conclusion
Delegation is a powerful tool to reduce boilerplate and enforce separation of concerns. Use standard delegates (lazy, observable) freely, but be cautious with custom ones.
You might also be interested in
SOLID Principles: Android Examples
Understanding SOLID principles in modern Android. Examples using Kotlin, Hilt, and MVVM.
Semantic Code Search Tools for AI Coding Agents: CocoIndex Code and CodeGraph
A comprehensive comparison of CocoIndex Code and CodeGraph — two AST-based semantic code search tools that dramatically reduce token consumption and accelerate code exploration for AI coding agents like Claude Code.
OpenSpec for Mobile Development: Spec-Driven Development in Android and Kotlin
How to apply OpenSpec in Android and Kotlin projects to keep AI agents aligned with architecture, with practical examples of change proposals, task validation, and living files.