Search⌘ K
AI Features

Decorator Design Pattern

Explore how the Decorator design pattern in Kotlin enables adding dynamic features such as logging and validation to classes without altering their original code. Understand interface delegation with the by keyword to compose behaviors flexibly and maintain clean, maintainable code.

In Prototype design pattern, we can create instances of classes with slightly (or not so slightly) different data. But, this raises a question:

What if we want to create a set of classes that all have slightly different behavior?

Well, since functions in Kotlin are first-class citizens, we could use the Prototype design pattern to achieve this aim. After all, creating a set of classes with slightly different behavior is what JavaScript does successfully. But there is another approach to the same problem. After all, design patterns are all about approaches.

By implementing the Decorator design pattern, we allow the users of our code to specify the abilities they want to add.

Enhancing a class

Let’s say that we have a rather simple class that registers all of the captains in the Star Trek universe along with their vessels:

open class StarTrekRepository {
private val starshipCaptains = mutableMapOf("USS
Enterprise" to "Jean-Luc Picard")
open fun getCaptain(starshipName: String): String {
return starshipCaptains[starshipName] ?: "Unknown"
}
open fun addCaptain(starshipName: String, captainName:
String) {
starshipCaptains[starshipName] = captainName
}
}
An open Star Trek repository class with methods for getting and adding starship captains

One day, your captain—sorry, scrum master—comes to you with an urgent requirement. From now on, every time someone searches for a captain, we must also log this into a console. However, there’s a catch to this simple task: you cannot modify the StarTrekRepository class ...