This post shows how to implement the Delegation Design Pattern in Kotlin.
We are using Kotlin 1.1
.
From Java
For some idea on how to use the design pattern and it the benefits it brings, please see:
https://turreta.com/blog/inheritance-and-delegation-design-pattern-examples-in-java/
To and in Kotlin
In Kotlin, it has what it calls Class Delegation facility that enables programmers to quickly implement the Delegation Pattern with the by-clause.
The codes below use this delegation facility but all methods of supposedly subclasses are overridden. At the very bottom, after the initial test, we’ll modify an existing “derived” class and test the codes again.
Canine.kt (Interface)
This interface ensures all classes (and supposedly “subclasses”) conform to specific set of behaviors.
1 2 3 4 | interface Canine { fun bark() fun getCanineType() : String } |
Dog.kt (Class / generic dog)
This class represents any dog (dog=canine). The term dog is a very broad classification.
1 2 3 4 5 6 7 8 9 10 | class Dog() : Canine { override fun bark() { print("arf-arf") } override fun getCanineType(): String { return "Generic Canine" } } |
Our generic dog barks “generically” and is labeled as “Generic Canine”.
Pitbull.kt
A Pitbull represents a specific kind of dog. It barks differently from the generic dog.
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Pitbull(b: Canine) : Canine by b { var canine: Canine = b override fun bark() { println("ruff-ruff") } override fun getCanineType(): String { var type: String = "Was " + canine.getCanineType() + ". Now a Pitbull"; return type; } } |
Pluto.kt
Pluto is another dog. It is a specific dog very different from our generic dog.
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Pluto(b: Canine) : Canine by b { var canine: Canine = b override fun bark() { println("goof") } override fun getCanineType(): String { var type: String = canine.getCanineType() + ". Now it's Pluto"; return type; } } |
Testing
This is our main function. Consider first the Pitbull object. During instantiation, an object of Dog class (generic dog) is passed to the contructor.
The Pitbull may use the characteristics of a generic dog using a Dog object. However, a Pitbull is a specific kind of a dog. Those generic characteristics are “replaced” with the Pitbull’s characteristics.
1 2 3 4 5 6 7 8 9 | fun main(args: Array<String>) { val a = Pitbull(Dog()) a.bark() println(a.getCanineType()) Pluto(a).bark() println(Pluto(a).getCanineType()) } |
This outputs:
1 2 3 4 | ruff-ruff Was Generic Canine. Now a Pitbull goof Was Generic Canine. Now a Pitbull. Now it's Pluto |
For Pluto, we passed in a Pitbull object. This means that Pluto has “evolved” from a Pitbull but has its own style of barking and whatnot.
By-clause and test again
Take note of the previously generated output. Now, we modify the Pluto class a bit.
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Pluto(b: Canine) : Canine by b { var canine: Canine = b // override fun bark() { // println("goof") // } override fun getCanineType(): String { var type: String = canine.getCanineType() + ". Now it's Pluto"; return type; } } |
Our codes now output:
1 2 3 4 | ruff-ruff Was Generic Canine. Now a Pitbull ruff-ruff Was Generic Canine. Now a Pitbull. Now it's Pluto |
Pluto now barks like a Pitbull.
References