Delegation & Object Declarations in Kotlin

In Kotlin, two advanced features—delegation and object declarations—help you build cleaner, more modular, and maintainable code. Using the analogy of an airplane’s design and control systems, we’ll explore how delegation lets you share behavior, and how object declarations let you create single-instance managers.

1. Why Delegation & Object Declarations Matter


2. Delegation in Kotlin

Delegation is when one class “hands off” part of its responsibilities to another class (delegate). In Kotlin, this works with interfaces and properties using the by keyword.

2.1 Interface Delegation (Airplane Example)

Suppose you have interfaces for flying and moving. You can implement those behaviors once and reuse via delegation.

Delegation Example: Airplane System

In this example, the Airplane class delegates its behaviors — flying and moving — to two separate systems: Flyable and Movable. Kotlin’s by keyword makes delegation easy and eliminates the need for redundant boilerplate code.


// Define interfaces representing behaviors
interface Flyable {
    fun fly(): String
}

interface Movable {
    fun move(): String
}

// JetFlySystem provides the actual implementation for flying
class JetFlySystem : Flyable {
    override fun fly() = "Jet-style takeoff and high speed ascent"
}

// TurbofanPropulsion provides implementation for ground and air movement
class TurbofanPropulsion : Movable {
    override fun move() = "Turbofan propulsion: taxi, accelerate, lift-off"
}

// Airplane delegates both Flyable and Movable interfaces to respective systems
class Airplane(
    private val flySystem: Flyable,       // delegate object for flying behavior
    private val propulsion: Movable       // delegate object for movement behavior
) : Flyable by flySystem,                 // Kotlin automatically forwards Flyable calls to flySystem
    Movable by propulsion {               // and Movable calls to propulsion
    // No need to implement fly() or move() manually — compiler does it for you!
}

fun main() {
    val plane = Airplane(JetFlySystem(), TurbofanPropulsion())
    
    // These calls are automatically delegated to their respective systems
    println(plane.fly())   // delegates to JetFlySystem.fly()
    println(plane.move())  // delegates to TurbofanPropulsion.move()
}
  

Output:


Jet-style takeoff and high speed ascent
Turbofan propulsion: taxi, accelerate, lift-off
  

Explanation

Notes

Output:


Jet-style takeoff and high speed ascent
Turbofan propulsion: taxi, accelerate, lift-off
  

Explanation:

2.2 Manual Delegation (Without `by` Keyword)

Sometimes you want to add extra logic around delegation (e.g., logging or safety checks). You can do it manually:


class AirplaneManual(
    private val flySystem: Flyable,
    private val propulsion: Movable
) : Flyable, Movable {

    override fun fly(): String {
        println("Pre-flight check: systems OK")
        val result = flySystem.fly()
        println("Post-flight log: flight completed")
        return result
    }

    override fun move(): String {
        println("Taxi check, wheels down")
        return propulsion.move()
    }
}

fun main() {
    val plane = AirplaneManual(JetFlySystem(), TurbofanPropulsion())
    println(plane.fly())
    println(plane.move())
}
  

Output:


Pre-flight check: systems OK
Jet-style takeoff and high speed ascent
Post-flight log: flight completed
Taxi check, wheels down
Turbofan propulsion: taxi, accelerate, lift-off
  

Explanation:


3. Property Delegation (Airplane Systems Monitoring)

Delegation also applies to properties — you can delegate how a property’s getter or setter behaves. Imagine monitoring fuel level or landing gear status.


import kotlin.properties.Delegates

class AircraftSystems {
    var fuelLevel: Int by Delegates.observable(100) { prop, old, new ->
        println("Fuel level changed from \$old% to \$new%")
    }
}

fun main() {
    val systems = AircraftSystems()
    systems.fuelLevel = 90
    systems.fuelLevel = 75
}
  

Output:


Fuel level changed from 100% to 90%
Fuel level changed from 90% to 75%
  

Explanation:


4. Object Declarations (Flight Control Manager)

In Kotlin, object declarations define a class and its single instance at once. This is perfect for single-point managers in aviation software.

4.1 Singleton Example


object FlightControlCenter {
    init {
        println("FlightControlCenter initialized – monitoring all flights")
    }
    fun registerFlight(flightId: String) {
        println("Flight \$flightId registered")
    }
}

fun main() {
    FlightControlCenter.registerFlight("A123")
    FlightControlCenter.registerFlight("B456")
}
  

Output:


FlightControlCenter initialized – monitoring all flights
Flight A123 registered
Flight B456 registered
  

Explanation:

4.2 Anonymous Object (One-off Flight Handler)

Sometimes you need a one‐time handler—like a temporary flight-monitor object.


val tempHandler = object {
    fun handleEmergency(flightId: String) {
        println("Emergency handler for flight \$flightId activated")
    }
}

fun main() {
    tempHandler.handleEmergency("C789")
}
  

Use Case: Quick callbacks, event handlers in aviation simulation environments.


5. Real-World Use Cases (Aviation Context)


6. Technical Interview Questions

7. Key Takeaways