委托给成员
组合行为
委托给成员 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
组合行为
现实中的对象通常需要组合多种能力。您不必从多个来源继承,而是可以将每项能力委托给专门的成员对象。
两个角色,一个类
假设一个类既要读取又要写入。请定义两个接口,并分别将它们委托给各自的实现。
interface Reader { fun read(): String }
interface Writer { fun write(s: String): String }
class FileReader : Reader { override fun read() = "contents" }
class FileWriter : Writer { override fun write(s: String) = "wrote " + s }
class FileIO(r: Reader, w: Writer) : Reader by r, Writer by w
fun main() {
val io = FileIO(FileReader(), FileWriter())
println(io.read())
println(io.write("data"))
}多个委托对象
一个类可以同时委托多个接口,并将每个接口委托给不同的成员。这样,类无需继承就能组合这些成员的行为。
interface Logger { fun log(m: String): String }
interface Validator { fun valid(m: String): Boolean }
class ConsoleLogger : Logger { override fun log(m: String) = "LOG: " + m }
class LengthValidator : Validator { override fun valid(m: String) = m.isNotEmpty() }
class Service(l: Logger, v: Validator) : Logger by l, Validator by v
fun main() {
val s = Service(ConsoleLogger(), LengthValidator())
println(s.valid("hi"))
println(s.log("started"))
}将委托对象存储为成员
当您需要在重写成员中引用委托对象时,请将它保存为构造函数属性。同一个实例会同时支持转发逻辑和您的自定义代码。
interface Cache { fun get(k: String): String }
class MapCache : Cache {
override fun get(k: String) = "value-of-" + k
}
class TracingCache(private val inner: Cache) : Cache by inner {
override fun get(k: String): String {
println("lookup " + k)
return inner.get(k)
}
}
fun main() {
println(TracingCache(MapCache()).get("id"))
}组合委托与自有状态
委托类可以在转发成员之外添加自己的属性和方法,从而丰富组合得到的对象。
interface Engine { fun start(): String }
class V8 : Engine { override fun start() = "vroom" }
class Car(e: Engine) : Engine by e {
var doors = 4
fun honk() = "beep"
}
fun main() {
val c = Car(V8())
println(c.start())
println(c.honk())
println(c.doors)
}替换实现
由于委托对象只是一个成员,您可以使用不同的底层实现来构造同一个包装器,从而在运行时选择行为。
interface Notifier { fun send(msg: String): String }
class EmailNotifier : Notifier { override fun send(msg: String) = "email: " + msg }
class SmsNotifier : Notifier { override fun send(msg: String) = "sms: " + msg }
class Alerts(n: Notifier) : Notifier by n
fun main() {
println(Alerts(EmailNotifier()).send("hi"))
println(Alerts(SmsNotifier()).send("hi"))
}委托给属性
by 后面的表达式可以是任何只求值一次的表达式,包括构造函数调用。它不一定必须是参数。
interface Greeter { fun greet() = "hi" }
class DefaultGreeter : Greeter
class Page : Greeter by DefaultGreeter()
fun main() {
println(Page().greet())
}避免菱形问题
类无法实现行为的多重继承,但将多个接口委托给不同成员,可以干净地避开经典的菱形问题。
interface A { fun a() = "A" }
interface B { fun b() = "B" }
class AImpl : A
class BImpl : B
class Combined : A by AImpl(), B by BImpl()
fun main() {
val c = Combined()
println(c.a() + c.b())
}面向组合进行设计
要实现良好的组合:
- 定义小而专注的接口
- 提供可复用的实现
- 在组合类中委托每个角色
这样可以让类保持灵活且易于测试。
成员委托回顾
委托给成员对象可以让类从各个部分组装行为。您可以组合多个接口、有选择地重写成员、替换实现并添加自己的状态——整个过程无需继承。
下一步:直接比较
您已经了解了委托的灵活性。下一课将直接比较委托与继承,帮助您知道何时选择哪一种方式。
快速检查
请检验您对成员委托的理解。
回顾
您学到了成员委托:
- 将多个接口委托给不同对象
- 有选择地重写成员并添加自有状态
- 在构造时替换实现
- 避免多重继承带来的问题
下一步:委托与继承。
用 AI 导师学习 Kotlin — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 51
- 课程
- 203
常见问题解答
「委托给成员」课时是免费的吗?
是的 — 「委托给成员」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「委托给成员」这节课中我会学到什么?
组合行为 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「委托给成员」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。