通过by操作符进行接口委托允许类将所有接口调用重定向到特定的委托对象。这减少了代码的重复,并实现了组合模式(composition)。
示例:
interface Logger { fun log(message: String) } class ConsoleLogger: Logger { override fun log(message: String) = println("LOG: $message") } class Service(logger: Logger): Logger by logger { fun doWork() { log("Service is working") } } val service = Service(ConsoleLogger()) service.doWork() // LOG: Service is working
与属性委托的区别:
val/var x by ...)应用于特定属性,并要求实现委托接口(例如,ReadWriteProperty)。优点:
缺点:
接口委托(
by)与通过字段传递对象实现接口有什么区别?
答案:
委托(通过by)自动通过委托对象实现所有接口的方法。如果只是将委托对象作为字段存储并手动调用其方法,则需要手动实现每个接口的方法——这会导致重复和错误。此外,通过by的委托提供了更好的可读性和更少的样板代码:
// 没有委托 class Service2(private val logger: Logger): Logger { override fun log(message: String) = logger.log(message) }
故事
在项目中,试图用手动方式实现Logger接口的装饰者模式,忘记实现接口的一个附加方法,而该方法后来被添加到Logger中。项目编译通过,但新功能无法工作,因为实现是“空实现”。通过by的接口委托可以避免这个错误:所有新方法都由委托自动实现。
故事
在通过by进行接口委托时,开发者重写了接口的一个方法,但遗忘了其他方法仍然通过委托调用。结果,部分功能表现得“非标准”——错误在业务方法的逻辑中很长时间未被捕获。
故事
尝试通过by实现多个接口的委托,方法交叉出现冲突——编译器报出了模糊性错误,不得不显式重写重复的方法,否则项目无法编译。