Extending on interfaces, you’ll see that not every conventional rule must be followed. The Kotlin language allows you to build code that makes little logical sense but could help define behaviors.
You’re going to break the rules and show that the interface can hold the data, and you can manipulate it to achieve remarkable results.
First, define a Shape interface:
interface Shape {
var name: String
get() = names[this]?.uppercase() ?: "Unknown shape"
set(value) {
names[this] = value
}
var vertices: Int
get() = vertexCount[this] ?: -1
set(value) {
vertexCount[this] = value
}
val details: String
get() = "The $name has $vertices vertices"
companion object {
private val names = mutableMapOf<Shape, String>()
private val vertexCount = mutableMapOf<Shape, Int>()
}
}
Did you see what you just did? You introduced companion object and overridden name and vertices getters and setters to store instances of type Shape, specifically classes implementing Shape.
Now, add a few shapes:
class Triangle : Shape
class Square : Shape
Triangle and Square implement the Shape interface. Since Shape has default implementations for all its properties, these class definitions are sufficient.
Now, play with it in the main() function:
fun main() {
val triangle = Triangle()
triangle.name = "Triangle"
triangle.vertices = 3
val square = Square()
square.name = "Square"
square.vertices = 5
println(triangle.details) // The TRIANGLE has 3 vertices
println(square.details) // The SQUARE has 5 vertices
}
All seems to be in order here. But make the names map public:
companion object {
val names = mutableMapOf<Shape, String>()
}
Now you can see that Shape has collected some information and is holding on to it. Add a few more lines to main():
Shape.names.forEach { name ->
println(name.value)
}
// Triangle
// Square
You’ll observe that the Shape interface retains a record of all its implementing classes that have been used at least once.
Note: This example is only for showcasing the capabilities of the Kotlin language class constructs by using interfaces for holding the data. Try this at your own risk. Potential risks include poor memory management and garbage collection. For example, the
Shapeinterface’s companion object holds references to all instances ofShapethat have been used. This can lead to memory leaks if these instances are no longer needed but can’t be garbage collected because theShapeinterface still holds a reference to them.