Claude Code for Kotlin Delegation Pattern Workflow
Kotlin’s delegation pattern is a powerful feature that allows you to delegate method calls to another object, promoting composition over inheritance and improving code reusability. When combined with Claude Code, you can efficiently implement, refactor, and maintain delegation patterns in your Kotlin projects. This guide provides practical workflows, code examples, and actionable strategies for using Claude Code in your Kotlin delegation pattern development.
Understanding Kotlin Delegation Basics
Kotlin provides first-class support for delegation through the by keyword. The language offers both built-in delegations like lazy, observable, and vetoable, as well as the ability to implement custom delegators. Understanding these fundamentals is essential before applying Claude Code to assist with your workflow.
Built-in Delegation Properties
Kotlin’s standard library includes several useful delegation patterns:
// Lazy delegation - value computed only on first access
val heavyObject by lazy {
println("Initializing heavy object...")
HeavyObject()
}
// Observable delegation - notifies on changes
var observedValue by observable("initial") { property, oldValue, newValue ->
println("Value changed from $oldValue to $newValue")
}
// Vetoable delegation - allows conditional changes
var positiveValue by vetoable(0) { _, _, newValue ->
newValue >= 0
}
When working with these patterns, Claude Code can help you generate appropriate implementations, explain behavior, and suggest optimal usage scenarios based on your specific requirements.
Setting Up Claude Code for Kotlin Development
Before diving into delegation patterns, ensure Claude Code is properly configured for your Kotlin project. Create a CLAUDE.md file in your project root to establish context-aware assistance:
# Project Context
- Language: Kotlin 1.9.x
- Build System: Gradle with Kotlin DSL
- Framework: Android/Server-side Kotlin
- Key Dependencies: Kotlin Coroutines, Spring Boot
# Code Conventions
- Use meaningful variable names
- Prefer immutable val over var when possible
- Follow official Kotlin style guide
- Document delegation usage in KDoc comments
This configuration helps Claude Code provide more accurate suggestions for delegation pattern implementations specific to your project structure and coding standards.
Implementing Custom Delegation Patterns
Custom delegation allows you to create reusable behavior that can be applied across different classes. Here’s a practical workflow for implementing custom delegators with Claude Code assistance.
Step 1: Define the Delegator Interface
Start by asking Claude Code to generate a clean interface for your delegator:
“Create a Kotlin interface for a property delegator that provides caching behavior with expiration”
Claude Code will generate:
interface CachedDelegate<V> {
operator fun getValue(thisRef: Any?, property: KProperty<*>): V
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: V)
}
class CachedValue<V>(
private val loader: () -> V,
private val expirationMs: Long = 60000
) : CachedDelegate<V> {
private var cached: V? = null
private var loadTime: Long = 0
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
val now = System.currentTimeMillis()
if (cached == null || now - loadTime > expirationMs) {
cached = loader()
loadTime = now
}
return cached!!
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
cached = value
loadTime = System.currentTimeMillis()
}
}
Step 2: Implement the Delegator Class
Ask Claude Code to extend the implementation with thread-safety:
“Add thread-safe implementation with double-checked locking to the CachedValue delegator”
Claude Code will enhance the implementation:
class CachedValue<V>(
private val loader: () -> V,
private val expirationMs: Long = 60000
) : ReadWriteProperty<Any?, V> {
@Volatile private var cached: V? = null
@Volatile private var loadTime: Long = 0
private val lock = ReentrantReadWriteLock()
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return lock.read {
val now = System.currentTimeMillis()
val current = cached
if (current == null || now - loadTime > expirationMs) {
lock.read.unlock()
lock.write {
// Double-check after acquiring write lock
if (cached == null || System.currentTimeMillis() - loadTime > expirationMs) {
cached = loader()
loadTime = System.currentTimeMillis()
}
}
lock.read.lock()
}
cached!!
}
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
lock.write {
cached = value
loadTime = System.currentTimeMillis()
}
}
}
Practical Delegation Patterns for Android Development
In Android development, delegation patterns are particularly useful for managing lifecycle-aware components, view binding, and dependency injection.
Lifecycle-Aware Delegation
Create a delegation pattern that automatically handles lifecycle events:
class LifecycleAwareDelegate<T>(
private val context: Context,
private val initializer: (Context) -> T
) : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: initializer(context).also { value = it }
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
fun <T> lifecycleAware(initializer: (Context) -> T): LifecycleAwareDelegate<T> {
return LifecycleAwareDelegate(requireContext(), initializer)
}
Use this pattern in your Android components:
class MyFragment : Fragment() {
// Automatically managed with fragment lifecycle
val database by lifecycleAware { Database.getInstance(it) }
val sharedPrefs by lifecycleAware {
it.getSharedPreferences("prefs", Context.MODE_PRIVATE)
}
}
Ask Claude Code for variations: “Create a lifecycle-aware delegate that automatically closes resources when the fragment is destroyed”
Refactoring to Delegation Patterns
Claude Code excels at helping you refactor existing code to use delegation patterns. This is particularly valuable when dealing with inheritance hierarchies that should be composition-based.
Common Refactoring Scenario
When you have:
open class BaseRepository {
open fun fetchUser(id: Int): User { /* implementation */ }
open fun saveUser(user: User) { /* implementation */ }
}
class UserRepository : BaseRepository() {
// Adds user-specific logic
}
Ask Claude Code to refactor:
“Refactor this inheritance hierarchy to use delegation instead, keeping the BaseRepository functionality while allowing composition”
Claude Code will generate:
interface Repository {
fun fetchUser(id: Int): User
fun saveUser(user: User)
}
class BaseRepositoryImpl : Repository {
override fun fetchUser(id: Int): User { /* implementation */ }
override fun saveUser(user: User) { /* implementation */ }
}
class UserRepository(
private val baseRepository: Repository = BaseRepositoryImpl()
) : Repository by baseRepository {
fun fetchUserWithCache(id: Int): User {
// Add caching logic while delegating base functionality
return baseRepository.fetchUser(id)
}
override fun saveUser(user: User) {
// Add validation before saving
require(user.isValid()) { "Invalid user data" }
baseRepository.saveUser(user)
}
}
Best Practices for Delegation Pattern Workflow
Following these practices ensures maintainable and effective delegation implementations:
1. Define Clear Interfaces
Always define interfaces for your delegators. This enables testing and provides clear contracts:
interface Logger {
fun log(message: String)
fun error(message: String, throwable: Throwable? = null)
}
class ConsoleLogger : Logger {
override fun log(message: String) = println(message)
override fun error(message: String, throwable: Throwable?)
= println("ERROR: $message, $throwable")
}
2. use Type-Safe Delegates
Use generic type parameters for reusability while maintaining type safety:
class NotNullDelegate<T : Any> : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException(
"Property ${property.name} has not been initialized"
)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
fun <T : Any> notNull(): NotNullDelegate<T> = NotNullDelegate()
3. Document Delegation Behavior
Use KDoc comments to explain delegation behavior, especially for custom delegates:
/**
* A delegator that provides lazy initialization with thread safety.
*
* @param T The type of value being delegated
* @param loader Lambda that produces the value on first access
* @param lock The lock to use for thread synchronization
*
* @see lazy
* @see kotlin.properties.ReadWriteProperty
*/
class SynchronizedLazyDelegate<T>(
private val loader: () -> T,
private val lock: Lock = ReentrantLock()
) : ReadWriteProperty<Any?, T> { /* implementation */ }
Troubleshooting Common Delegation Issues
When working with delegation patterns, you may encounter issues that Claude Code can help diagnose and resolve.
Property Delegate Type Mismatch
If you see type mismatch errors with delegates, ensure your delegate matches the property type:
// Wrong - type mismatch
val stringProperty: String by lazy { 42 } // Error: Int cannot be assigned to String
// Correct - matching types
val stringProperty: String by lazy { "42" }
val intProperty: Int by lazy { 42 }
Ask Claude Code: “Fix this type mismatch in the delegation” and provide the code for immediate correction.
Delegate Not Found Errors
When using custom delegates, ensure proper import statements and interface implementations:
import kotlin.properties.ReadWriteProperty
// Verify your delegate implements the correct interface
class MyDelegate<V> : ReadWriteProperty<Any?, V> { /* ... */ }
Conclusion
Kotlin’s delegation patterns, combined with Claude Code’s assistance, provide a powerful workflow for building maintainable, reusable code. By using Claude Code’s ability to generate, explain, and refactor delegation implementations, you can accelerate development while ensuring best practices. Remember to define clear interfaces, document behavior, and use built-in delegates where appropriate. With these patterns in your toolkit, you’ll write more elegant and composable Kotlin code.
Related Reading
- Claude Code for Beginners: Complete Getting Started Guide
- Best Claude Skills for Developers in 2026
- Claude Skills Guides Hub
Built by theluckystrike — More at zovo.one