Kotlin Academy · 课时

委托与继承

选择组合

第 3 / 4 课13 个步骤

委托与继承 是 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. by 关键字
  2. 委托给成员
  3. 委托与继承
  4. 实用模式
← 返回 Kotlin Academy