委托与继承
选择组合
委托与继承 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
两种复用方式
继承和委托都可以复用行为。继承表示一个类是一种另一个类。委托表示一个类拥有一个它会转发调用的协作者。
经典建议是:优先使用组合,而不是继承。
继承示例
使用继承时,子类会扩展基类并重写成员。在 Kotlin 中,基类必须声明为 open。
open class Animal {
open fun sound() = "..."
}
class Dog : Animal() {
override fun sound() = "woof"
}
fun main() {
println(Dog().sound())
}委托示例
通过委托实现相同的复用:行为由类转发请求的成员提供。
interface Sound { fun sound(): String }
class Bark : Sound { override fun sound() = "woof" }
class Dog(s: Sound) : Sound by s
fun main() {
println(Dog(Bark()).sound())
}脆弱基类
继承会使子类与父类的内部实现紧密耦合。基类中的改动可能在不知不觉间破坏子类,这就是脆弱基类问题。委托只依赖接口。
封装
子类可以访问受保护成员并重写钩子,从而窥视父类的内部。委托类只能看到公共接口,因此能够保留封装性。
interface Counter { fun increment(): Int }
class SimpleCounter : Counter {
private var n = 0
override fun increment(): Int { n++; return n }
}
class GuardedCounter(private val c: Counter) : Counter by c {
override fun increment(): Int {
println("incrementing")
return c.increment()
}
}
fun main() {
val g = GuardedCounter(SimpleCounter())
println(g.increment())
println(g.increment())
}运行时的灵活性
继承在编译时固定父类。委托允许您在运行时注入不同的实现,并通过伪对象轻松进行测试。
interface Clock { fun now(): Int }
class RealClock : Clock { override fun now() = 100 }
class FakeClock : Clock { override fun now() = 0 }
class Timer(c: Clock) : Clock by c
fun main() {
println(Timer(RealClock()).now())
println(Timer(FakeClock()).now()) // easy to test
}多种行为
一个类只能扩展一个父类,但可以委托给多个接口。委托适合组合多种能力,并且能够随规模增长。
interface Walk { fun walk() = "walking" }
interface Swim { fun swim() = "swimming" }
class Walker : Walk
class Swimmer : Swim
class Amphibian : Walk by Walker(), Swim by Swimmer()
fun main() {
val a = Amphibian()
println(a.walk() + ", " + a.swim())
}适合使用继承的场景
如果存在真正的是一个关系,并且层次结构稳定且专为扩展而设计,继承仍然是正确的选择:例如密封类型族、框架基类,以及针对共享抽象类型的多态。
sealed class Shape
class Circle(val r: Double) : Shape()
class Square(val s: Double) : Shape()
fun area(shape: Shape) = when (shape) {
is Circle -> 3.14 * shape.r * shape.r
is Square -> shape.s * shape.s
}
fun main() {
println(area(Circle(2.0)))
}适合使用委托的场景
在以下情况下,请选择委托:
- 在互不相关的类型之间复用行为
- 组合多种能力
- 降低耦合并简化测试
- 包装和装饰现有实现
并列比较
继承:一个父类、紧密耦合、在编译时固定、是一个。委托:多个协作者、松散耦合、可在运行时替换、拥有。Kotlin 通过 by 让组合的成本很低,使设计更倾向于组合。
实用的默认选择
一个很好的规则是:从委托开始。只有在真正稳定的是一个层次结构形成后,才切换到继承。这样可以让设计保持灵活,并能更好地应对变化。
快速检查
请测试您对委托与继承的理解。
回顾
您比较了这两种方式:
- 继承:是一个、单个父类、紧密耦合
- 委托:拥有、多个协作者、松散耦合
- 优先使用组合;在稳定的“是一个”层次结构中使用继承
下一步:使用委托实现实用的装饰器模式。
用 AI 导师学习 Kotlin — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 51
- 课程
- 203
常见问题解答
「委托与继承」课时是免费的吗?
是的 — 「委托与继承」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「委托与继承」这节课中我会学到什么?
选择组合 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「委托与继承」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。