A class that implements an interface may implement all required methods by delegating to a specified delegate instance. In the following code, we've defined a SettingsProvider interface that is then implemented by a SettingsManager object:
interface SettingsProvider {
fun getSetting(key: String) : String
}
object SettingsManager : SettingsProvider {
private val map = HashMap<String, String>()
override fun getSetting(key: String)
= map.getOrDefault(key, "")
}
Now, we want to define a UserManager class that will implement SettingsProvider by delegating to SettingsManager:
class UserManager : SettingsProvider by SettingsManager
We start by declaring the class name and adding the SettingsProvider interface, but then we add the by keyword and specify a delegate object that implements SettingsProvider on behalf of UserManager. In this case, because SettingsManager implements SettingsProvider, it can act as the delegate for UserManager.
In this example, we are using an object, SettingsManager, to act as the delegate. But what if we want to be able to swap out delegates by passing them through the constructor? In that case, we can define a constructor parameter and then delegate to that parameter instead, as in the following example:
object SettingsManager : SettingsProvider {
private val map = HashMap<String, String>()
override fun getSetting(key: String)
= map.getOrDefault(key, "")
}
class UserManager(settingsProvider: SettingsProvider) : SettingsProvider by settingsProvider
After these changes, we can pass different instances of SettingsProvider to UserManager, and it will continue to delegate to whichever SettingsProvider class is passed in.