【Kotlin系列06】面向对象进阶:从接口到多态,设计灵活可扩展的代码

82 阅读9分钟

引言:那个让我重构的"万能类"

还记得刚入行时,我写过一个"万能"的DataManager类,处理所有数据相关的操作:

// 反面教材:上帝类(God Class)
class DataManager {
    fun loadUserFromDatabase() { ... }
    fun loadUserFromApi() { ... }
    fun loadUserFromCache() { ... }
    fun saveUser() { ... }
    fun loadProductFromDatabase() { ... }
    fun loadProductFromApi() { ... }
    fun saveProduct() { ... }
    // ... 还有100多个方法
}

这个类超过2000行代码,维护起来就像拆炸弹。每次添加新功能,都要担心会不会影响其他功能。

后来,资深同事教我用接口和抽象类重构:

// 正确做法:基于接口的设计
interface DataSource<T> {
    suspend fun load(id: String): T?
    suspend fun save(item: T)
}

// 不同的实现
class DatabaseDataSource<T> : DataSource<T> { ... }
class ApiDataSource<T> : DataSource<T> { ... }
class CacheDataSource<T> : DataSource<T> { ... }

// 组合使用
class Repository<T>(
    private val remote: DataSource<T>,
    private val local: DataSource<T>,
    private val cache: DataSource<T>
) {
    suspend fun get(id: String): T? {
        return cache.load(id)
            ?: local.load(id)
            ?: remote.load(id)?.also {
                local.save(it)
                cache.save(it)
            }
    }
}

代码变得清晰、灵活、易测试!这就是面向对象设计的威力。

今天,我们就来深入探索Kotlin的OOP高级特性。

接口(Interface):定义契约

什么是接口

接口定义了类应该做什么,但不规定怎么做。就像合同约定了双方的责任,但不管具体如何执行。

interface Clickable {
    fun click()  // 抽象方法(必须实现)
    fun showInfo() {  // 默认实现(可选覆盖)
        println("Clickable element")
    }
}

class Button : Clickable {
    override fun click() {
        println("Button clicked!")
    }
    // showInfo()可以不覆盖,使用默认实现
}

class Link : Clickable {
    override fun click() {
        println("Link clicked!")
    }

    override fun showInfo() {  // 覆盖默认实现
        println("This is a link")
    }
}

06-01-interface-implementation.png

接口可以包含什么

interface Repository {
    // 1. 抽象属性(必须实现)
    val name: String

    // 2. 属性的getter(可以有默认实现)
    val count: Int
        get() = 0

    // 3. 抽象方法
    fun save(data: String)

    // 4. 带默认实现的方法
    fun log(message: String) {
        println("[$name] $message")
    }

    // 5. 私有方法(Kotlin 1.4+)
    private fun validate(data: String): Boolean {
        return data.isNotEmpty()
    }

    fun saveIfValid(data: String) {
        if (validate(data)) {
            save(data)
        }
    }
}
**接口 vs 抽象类的选择**: - 接口:定义"能做什么"(行为契约),支持多继承 - 抽象类:定义"是什么"(共同特征),只能单继承,可以有状态

经验法则:优先使用接口,只有在需要共享状态或构造函数时才用抽象类。

实现多个接口

Kotlin支持实现多个接口,这是实现组合优于继承的重要方式:

interface Drawable {
    fun draw()
}

interface Clickable {
    fun click()
}

interface Draggable {
    fun drag()
    fun drop()
}

// 实现多个接口
class Button : Drawable, Clickable, Draggable {
    override fun draw() {
        println("Drawing button")
    }

    override fun click() {
        println("Button clicked")
    }

    override fun drag() {
        println("Button dragging")
    }

    override fun drop() {
        println("Button dropped")
    }
}

解决冲突

当多个接口有同名方法时,必须显式覆盖:

interface A {
    fun foo() {
        println("A.foo()")
    }
}

interface B {
    fun foo() {
        println("B.foo()")
    }
}

class C : A, B {
    // 必须覆盖,因为A和B都有foo()的默认实现
    override fun foo() {
        super<A>.foo()  // 调用A的实现
        super<B>.foo()  // 调用B的实现
        println("C.foo()")  // 自己的实现
    }
}

抽象类(Abstract Class):共享实现

什么是抽象类

抽象类是不能直接实例化的类,用于定义子类的公共行为和状态。

abstract class Shape {
    // 具体属性(子类继承)
    var color: String = "black"

    // 抽象属性(子类必须实现)
    abstract val area: Double

    // 具体方法(子类继承)
    fun describe() {
        println("A $color shape with area $area")
    }

    // 抽象方法(子类必须实现)
    abstract fun draw()
}

class Circle(val radius: Double) : Shape() {
    // 实现抽象属性
    override val area: Double
        get() = Math.PI * radius * radius

    // 实现抽象方法
    override fun draw() {
        println("Drawing circle with radius $radius")
    }
}

class Rectangle(val width: Double, val height: Double) : Shape() {
    override val area: Double
        get() = width * height

    override fun draw() {
        println("Drawing rectangle ${width}x${height}")
    }
}

// 使用
val circle = Circle(5.0)
circle.color = "red"
circle.describe()  // A red shape with area 78.54
circle.draw()      // Drawing circle with radius 5.0

抽象类 vs 接口

特性接口抽象类
状态(属性)不能有backing field可以有
构造函数不能有可以有
多继承支持不支持
初始化块不能有可以有
访问修饰符总是public可以是任意
使用场景定义行为契约定义共同实现
// 接口:不能有状态
interface Flyable {
    val speed: Int  // ❌ 不能有backing field
        get() = 100  // ✅ 只能有getter
}

// 抽象类:可以有状态
abstract class Animal {
    var age: Int = 0  // ✅ 可以有backing field

    init {
        println("Animal created")  // ✅ 可以有初始化块
    }

    constructor(age: Int) {  // ✅ 可以有构造函数
        this.age = age
    }
}

模板方法模式

抽象类常用于实现模板方法模式:定义算法骨架,子类实现具体步骤。

abstract class DataProcessor {
    // 模板方法:定义处理流程
    fun process() {
        val data = loadData()
        val validated = validate(data)
        if (validated) {
            val transformed = transform(data)
            save(transformed)
        }
    }

    // 抽象方法:子类必须实现
    protected abstract fun loadData(): String
    protected abstract fun transform(data: String): String
    protected abstract fun save(data: String)

    // 钩子方法:子类可以覆盖
    protected open fun validate(data: String): Boolean {
        return data.isNotEmpty()
    }
}

class CsvProcessor : DataProcessor() {
    override fun loadData(): String {
        return "csv data"
    }

    override fun transform(data: String): String {
        return data.split(",").joinToString("|")
    }

    override fun save(data: String) {
        println("Saving: $data")
    }
}

// 使用
val processor = CsvProcessor()
processor.process()

多态(Polymorphism):一个接口,多种实现

什么是多态

多态是OOP的核心特性,允许用父类型引用指向子类型对象,运行时根据实际类型执行相应的方法。

open class Animal {
    open fun makeSound() {
        println("Some sound")
    }
}

class Dog : Animal() {
    override fun makeSound() {
        println("Woof!")
    }
}

class Cat : Animal() {
    override fun makeSound() {
        println("Meow!")
    }
}

// 多态:用父类型引用子类对象
val animals: List<Animal> = listOf(
    Dog(),
    Cat(),
    Dog()
)

// 运行时多态:根据实际类型调用方法
animals.forEach { it.makeSound() }
// 输出:
// Woof!
// Meow!
// Woof!

06-02-polymorphism.png

多态的类型

1. 方法多态(Method Polymorphism)

最常见的多态形式,通过方法覆盖实现:

abstract class PaymentMethod {
    abstract fun pay(amount: Double): Boolean
    abstract fun refund(amount: Double): Boolean
}

class CreditCard : PaymentMethod() {
    override fun pay(amount: Double): Boolean {
        println("Paying $$amount with credit card")
        return true
    }

    override fun refund(amount: Double): Boolean {
        println("Refunding $$amount to credit card")
        return true
    }
}

class Alipay : PaymentMethod() {
    override fun pay(amount: Double): Boolean {
        println("Paying ¥$amount with Alipay")
        return true
    }

    override fun refund(amount: Double): Boolean {
        println("Refunding ¥$amount to Alipay")
        return true
    }
}

// 多态使用
fun processPayment(method: PaymentMethod, amount: Double) {
    if (method.pay(amount)) {
        println("Payment successful")
    }
}

processPayment(CreditCard(), 100.0)
processPayment(Alipay(), 500.0)

2. 参数多态(Parametric Polymorphism)

通过泛型实现,我们将在后续文章详细讲解:

// 泛型函数:适用于任何类型
fun <T> swap(a: T, b: T): Pair<T, T> {
    return Pair(b, a)
}

val (x, y) = swap(1, 2)        // 自动推断为Int
val (s1, s2) = swap("a", "b")  // 自动推断为String

多态的优势

// 不使用多态:代码冗长,难以扩展
fun handlePayment(paymentType: String, amount: Double) {
    when (paymentType) {
        "credit_card" -> {
            println("Paying $$amount with credit card")
        }
        "alipay" -> {
            println("Paying ¥$amount with Alipay")
        }
        "wechat" -> {
            println("Paying ¥$amount with WeChat Pay")
        }
        // 每次新增支付方式都要修改这里
        else -> throw IllegalArgumentException("Unknown payment type")
    }
}

// 使用多态:代码简洁,易于扩展
abstract class PaymentMethod {
    abstract fun pay(amount: Double)
}

class CreditCard : PaymentMethod() {
    override fun pay(amount: Double) {
        println("Paying $$amount with credit card")
    }
}

class Alipay : PaymentMethod() {
    override fun pay(amount: Double) {
        println("Paying ¥$amount with Alipay")
    }
}

// 新增支付方式:只需新增类,不修改现有代码(开放-封闭原则)
class WeChatPay : PaymentMethod() {
    override fun pay(amount: Double) {
        println("Paying ¥$amount with WeChat Pay")
    }
}

fun handlePayment(method: PaymentMethod, amount: Double) {
    method.pay(amount)  // 简洁!
}

sealed类:密封的类层次

sealed类是Kotlin的特色功能,用于表示受限的类层次,所有子类必须在同一文件中定义。

基本用法

sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

// 使用when表达式,编译器知道所有可能的子类
fun <T> handleResult(result: Result<T>) {
    when (result) {
        is Result.Success -> println("Success: ${result.data}")
        is Result.Error -> println("Error: ${result.exception.message}")
        is Result.Loading -> println("Loading...")
        // 不需要else分支!编译器知道所有情况
    }
}

sealed类 vs enum类

特性enumsealed class
实例数量固定,编译时确定可以有多个实例
携带数据每个常量相同类型每个子类可以不同
继承不能有子类可以有子类
使用场景简单枚举复杂的状态/结果
// enum:简单枚举
enum class Direction {
    NORTH, SOUTH, EAST, WEST
}

// sealed:复杂类型
sealed class NetworkResult {
    data class Success(val data: String, val timestamp: Long) : NetworkResult()
    data class Error(val code: Int, val message: String) : NetworkResult()
    object Loading : NetworkResult()
    object Idle : NetworkResult()
}

实战:状态管理

sealed class UiState<out T> {
    object Idle : UiState<Nothing>()
    object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val message: String, val throwable: Throwable? = null) : UiState<Nothing>()
}

class UserViewModel {
    private val _uiState = MutableStateFlow<UiState<User>>(UiState.Idle)
    val uiState: StateFlow<UiState<User>> = _uiState

    suspend fun loadUser(id: String) {
        _uiState.value = UiState.Loading
        try {
            val user = userRepository.getUser(id)
            _uiState.value = UiState.Success(user)
        } catch (e: Exception) {
            _uiState.value = UiState.Error("Failed to load user", e)
        }
    }
}

// UI层使用
viewModel.uiState.collect { state ->
    when (state) {
        is UiState.Idle -> {
            // 显示初始状态
        }
        is UiState.Loading -> {
            // 显示加载中
            showLoading()
        }
        is UiState.Success -> {
            // 显示数据
            showUser(state.data)
        }
        is UiState.Error -> {
            // 显示错误
            showError(state.message)
        }
    }
}

委托(Delegation):组合优于继承

类委托(Class Delegation)

Kotlin原生支持委托模式,无需手动编写转发代码:

interface Printer {
    fun print(message: String)
    fun status(): String
}

class ConsolePrinter : Printer {
    override fun print(message: String) {
        println("Console: $message")
    }

    override fun status(): String {
        return "Console printer ready"
    }
}

class FilePrinter(private val filename: String) : Printer {
    override fun print(message: String) {
        println("Writing to $filename: $message")
    }

    override fun status(): String {
        return "File printer ready ($filename)"
    }
}

// 不使用委托:手动转发所有方法
class PrinterManager(private val printer: Printer) : Printer {
    override fun print(message: String) {
        printer.print(message)  // 转发
    }

    override fun status(): String {
        return printer.status()  // 转发
    }
}

// 使用委托:自动转发
class PrinterManager2(printer: Printer) : Printer by printer {
    // 所有方法自动委托给printer
    // 可以选择性覆盖
    override fun print(message: String) {
        println("PrinterManager: Logging...")
        super.print(message)  // 调用委托对象的方法
    }
}

// 使用
val manager = PrinterManager2(ConsolePrinter())
manager.print("Hello")
println(manager.status())

06-03-class-delegation.png

委托的优势

// 示例:添加日志功能
interface Logger {
    fun log(message: String)
}

class ConsoleLogger : Logger {
    override fun log(message: String) {
        println("[LOG] $message")
    }
}

// 传统方式:继承
class LoggedPrinter : ConsolePrinter() {
    private val logger = ConsoleLogger()

    override fun print(message: String) {
        logger.log("Printing: $message")
        super.print(message)
    }
}

// Kotlin方式:委托 + 装饰
class LoggedPrinter2(
    private val printer: Printer,
    private val logger: Logger
) : Printer by printer {
    override fun print(message: String) {
        logger.log("Printing: $message")
        printer.print(message)
    }
}

// 灵活组合
val printer1 = LoggedPrinter2(ConsolePrinter(), ConsoleLogger())
val printer2 = LoggedPrinter2(FilePrinter("output.txt"), ConsoleLogger())
**组合优于继承**: - 继承是"is-a"关系,紧耦合,难以改变 - 组合是"has-a"关系,松耦合,灵活组合 - Kotlin的委托让组合像继承一样简洁

何时用继承:只有在真正的"is-a"关系时(如Dog是Animal) 何时用委托:需要复用功能但不是"is-a"关系时(如带日志的打印机)

实战:构建可扩展的消息通知系统

让我们综合运用所学知识,构建一个完整的消息通知系统:

// 1. 定义接口:消息发送器
interface MessageSender {
    suspend fun send(to: String, content: String): Result<Unit>
    fun isAvailable(): Boolean
}

// 2. 不同的实现
class EmailSender : MessageSender {
    override suspend fun send(to: String, content: String): Result<Unit> {
        return try {
            // 模拟发送邮件
            delay(100)
            println("Email sent to $to: $content")
            Result.success(Unit)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    override fun isAvailable(): Boolean = true
}

class SmsSender : MessageSender {
    override suspend fun send(to: String, content: String): Result<Unit> {
        return try {
            delay(50)
            println("SMS sent to $to: $content")
            Result.success(Unit)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    override fun isAvailable(): Boolean = true
}

class PushSender : MessageSender {
    override suspend fun send(to: String, content: String): Result<Unit> {
        return try {
            delay(20)
            println("Push notification sent to $to: $content")
            Result.success(Unit)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    override fun isAvailable(): Boolean = true
}

// 3. 抽象类:带重试逻辑的发送器
abstract class RetryableSender : MessageSender {
    protected abstract val maxRetries: Int

    abstract suspend fun doSend(to: String, content: String): Result<Unit>

    override suspend fun send(to: String, content: String): Result<Unit> {
        repeat(maxRetries) { attempt ->
            val result = doSend(to, content)
            if (result.isSuccess) {
                return result
            }
            if (attempt < maxRetries - 1) {
                println("Retry ${attempt + 1}/$maxRetries")
                delay(1000L * (attempt + 1))
            }
        }
        return Result.failure(Exception("Failed after $maxRetries attempts"))
    }
}

class RetryableEmailSender : RetryableSender() {
    override val maxRetries = 3
    private val emailSender = EmailSender()

    override suspend fun doSend(to: String, content: String): Result<Unit> {
        return emailSender.send(to, content)
    }

    override fun isAvailable(): Boolean = emailSender.isAvailable()
}

// 4. 委托:带日志的发送器
class LoggedSender(
    private val sender: MessageSender,
    private val logger: (String) -> Unit
) : MessageSender by sender {
    override suspend fun send(to: String, content: String): Result<Unit> {
        logger("Sending message to $to")
        val result = sender.send(to, content)
        if (result.isSuccess) {
            logger("Message sent successfully")
        } else {
            logger("Message failed: ${result.exceptionOrNull()?.message}")
        }
        return result
    }
}

// 5. 策略模式:组合多个发送器
class MultiChannelSender(
    private val senders: List<MessageSender>
) : MessageSender {
    override suspend fun send(to: String, content: String): Result<Unit> {
        val availableSenders = senders.filter { it.isAvailable() }
        if (availableSenders.isEmpty()) {
            return Result.failure(Exception("No available senders"))
        }

        // 并行发送
        val results = availableSenders.map { sender ->
            async {
                sender.send(to, content)
            }
        }.awaitAll()

        // 只要有一个成功就算成功
        return if (results.any { it.isSuccess }) {
            Result.success(Unit)
        } else {
            Result.failure(Exception("All senders failed"))
        }
    }

    override fun isAvailable(): Boolean {
        return senders.any { it.isAvailable() }
    }
}

// 6. 使用sealed类表示发送结果
sealed class SendResult {
    data class Success(val channel: String, val timestamp: Long) : SendResult()
    data class Failure(val channel: String, val error: String) : SendResult()
    data class PartialSuccess(val succeeded: List<String>, val failed: List<String>) : SendResult()
}

// 7. 通知管理器
class NotificationManager(
    private val emailSender: MessageSender,
    private val smsSender: MessageSender,
    private val pushSender: MessageSender
) {
    suspend fun notify(
        userId: String,
        message: String,
        channels: Set<String> = setOf("email", "sms", "push")
    ): SendResult {
        val results = mutableMapOf<String, Boolean>()

        if ("email" in channels) {
            results["email"] = emailSender.send(userId, message).isSuccess
        }
        if ("sms" in channels) {
            results["sms"] = smsSender.send(userId, message).isSuccess
        }
        if ("push" in channels) {
            results["push"] = pushSender.send(userId, message).isSuccess
        }

        val succeeded = results.filter { it.value }.keys.toList()
        val failed = results.filter { !it.value }.keys.toList()

        return when {
            failed.isEmpty() -> SendResult.Success(
                channel = succeeded.joinToString(","),
                timestamp = System.currentTimeMillis()
            )
            succeeded.isEmpty() -> SendResult.Failure(
                channel = failed.joinToString(","),
                error = "All channels failed"
            )
            else -> SendResult.PartialSuccess(
                succeeded = succeeded,
                failed = failed
            )
        }
    }
}

// 使用示例
suspend fun main() {
    // 创建基础发送器
    val emailSender = RetryableEmailSender()
    val smsSender = SmsSender()
    val pushSender = PushSender()

    // 用日志包装
    val loggedEmailSender = LoggedSender(emailSender) { msg ->
        println("[LOG] $msg")
    }

    // 创建通知管理器
    val notificationManager = NotificationManager(
        emailSender = loggedEmailSender,
        smsSender = smsSender,
        pushSender = pushSender
    )

    // 发送通知
    val result = notificationManager.notify(
        userId = "user123",
        message = "Your order has been shipped!",
        channels = setOf("email", "sms", "push")
    )

    // 处理结果
    when (result) {
        is SendResult.Success -> {
            println("Notification sent via: ${result.channel}")
        }
        is SendResult.Failure -> {
            println("Failed to send via: ${result.channel}")
            println("Error: ${result.error}")
        }
        is SendResult.PartialSuccess -> {
            println("Succeeded: ${result.succeeded}")
            println("Failed: ${result.failed}")
        }
    }
}

常见问题

Q1: 什么时候用接口,什么时候用抽象类?

决策树

需要多继承?
├─ 是 → 使用接口
└─ 否
   └─ 需要共享状态或构造函数?
      ├─ 是 → 使用抽象类
      └─ 否 → 使用接口(更灵活)

具体场景

// ✅ 接口:定义行为契约
interface Clickable {
    fun click()
}

interface Drawable {
    fun draw()
}

// 可以实现多个
class Button : Clickable, Drawable {
    override fun click() { ... }
    override fun draw() { ... }
}

// ✅ 抽象类:共享状态和实现
abstract class View {
    var x: Int = 0  // 共享状态
    var y: Int = 0

    constructor(x: Int, y: Int) {  // 构造函数
        this.x = x
        this.y = y
    }

    fun move(dx: Int, dy: Int) {  // 共享实现
        x += dx
        y += dy
    }

    abstract fun render()  // 子类必须实现
}

Q2: sealed类和enum有什么区别?

特性enumsealed class
实例化编译时固定可以有多个实例
数据类型所有常量相同每个子类可以不同
继承不能继承可以有复杂继承
构造参数所有常量相同每个子类可以不同
// enum:简单状态
enum class Status {
    PENDING,
    APPROVED,
    REJECTED
}

// sealed:复杂状态,携带不同数据
sealed class ApiResponse {
    data class Success(val data: String, val code: Int) : ApiResponse()
    data class Error(val message: String, val exception: Throwable?) : ApiResponse()
    object Loading : ApiResponse()
}

Q3: 为什么要用委托而不是继承?

继承的问题

  1. 紧耦合,子类依赖父类实现
  2. 违反单一职责原则(为了复用功能而继承)
  3. 难以改变行为(编译时确定)

委托的优势

  1. 松耦合,可以运行时替换
  2. 符合单一职责原则
  3. 更灵活的组合
// ❌ 继承:紧耦合
class LoggedList<T> : ArrayList<T>() {
    override fun add(element: T): Boolean {
        println("Adding $element")
        return super.add(element)
    }
    // 如果ArrayList实现改变,这里可能出问题
}

// ✅ 委托:松耦合
class LoggedList<T>(
    private val list: MutableList<T> = ArrayList()
) : MutableList<T> by list {
    override fun add(element: T): Boolean {
        println("Adding $element")
        return list.add(element)
    }
    // 可以轻松替换底层实现
}

// 更灵活
val list1 = LoggedList<Int>()  // 默认ArrayList
val list2 = LoggedList<Int>(LinkedList())  // 使用LinkedList

Q4: 多态是如何实现的?

Kotlin(和JVM)使用**虚方法表(vtable)**实现多态:

// 编译后的虚方法表
class Animal {
    open fun makeSound() { ... }
    // vtable: [makeSound -> Animal.makeSound]
}

class Dog : Animal() {
    override fun makeSound() { ... }
    // vtable: [makeSound -> Dog.makeSound]  // 覆盖
}

// 运行时
val animal: Animal = Dog()
animal.makeSound()  // 查找Dog的vtable,调用Dog.makeSound()

性能:虚方法调用比直接调用慢约2-5ns,在绝大多数情况下可以忽略不计。

总结

本文深入探讨了Kotlin面向对象编程的高级特性:

1. 接口(Interface)

  • 定义行为契约,支持默认实现
  • 支持多继承,灵活组合
  • 解决方法冲突

2. 抽象类(Abstract Class)

  • 共享状态和实现
  • 模板方法模式
  • 与接口的选择

3. 多态(Polymorphism)

  • 一个接口,多种实现
  • 方法多态、参数多态
  • 提高代码的灵活性和可扩展性

4. sealed类

  • 受限的类层次
  • 完善的when表达式
  • 状态管理的最佳实践

5. 委托(Delegation)

  • 组合优于继承
  • 类委托的语法糖
  • 装饰模式的简洁实现

6. 设计原则

  • 开放-封闭原则(对扩展开放,对修改封闭)
  • 单一职责原则
  • 依赖倒置原则(依赖抽象而非具体)

下一篇文章我们将学习Kotlin类型系统深度解析,探索可空类型、类型检查与智能转换。

练习题

练习1:实现图形绘制系统

// TODO 1: 定义Shape接口
interface Shape {
    // 计算面积
    // 计算周长
    // 绘制
}

// TODO 2: 实现不同的图形
class Circle { ... }
class Rectangle { ... }
class Triangle { ... }

// TODO 3: 实现组合图形(Composite模式)
class CompositeShape { ... }

// TODO 4: 使用sealed类表示绘制结果
sealed class DrawResult { ... }

// 测试
fun main() {
    val shapes = listOf<Shape>(
        Circle(5.0),
        Rectangle(4.0, 6.0),
        Triangle(3.0, 4.0, 5.0)
    )

    shapes.forEach { shape ->
        println("Area: ${shape.area()}")
        println("Perimeter: ${shape.perimeter()}")
        shape.draw()
    }
}

练习2:实现可扩展的日志系统

// TODO 1: 定义Logger接口
interface Logger {
    fun log(level: LogLevel, message: String)
}

// TODO 2: 实现不同的Logger
class ConsoleLogger : Logger { ... }
class FileLogger(filename: String) : Logger { ... }
class RemoteLogger(endpoint: String) : Logger { ... }

// TODO 3: 使用委托实现带过滤的Logger
class FilteredLogger(
    logger: Logger,
    minLevel: LogLevel
) : Logger by logger {
    // 只记录大于等于minLevel的日志
}

// TODO 4: 使用sealed类表示日志级别
sealed class LogLevel {
    object Debug : LogLevel()
    object Info : LogLevel()
    object Warning : LogLevel()
    object Error : LogLevel()
}

// 测试
fun main() {
    val logger = FilteredLogger(
        ConsoleLogger(),
        LogLevel.Info
    )

    logger.log(LogLevel.Debug, "This won't show")
    logger.log(LogLevel.Info, "This will show")
}

练习3:实现职责链模式

// TODO 1: 定义Handler抽象类
abstract class Handler {
    protected var next: Handler? = null

    fun setNext(handler: Handler): Handler {
        next = handler
        return handler
    }

    abstract fun handle(request: Request): Response?
}

// TODO 2: 实现不同的Handler
class AuthHandler : Handler() { ... }
class ValidationHandler : Handler() { ... }
class BusinessHandler : Handler() { ... }

// TODO 3: 使用sealed类表示请求和响应
sealed class Request { ... }
sealed class Response { ... }

// 测试
fun main() {
    val chain = AuthHandler().apply {
        setNext(ValidationHandler()).apply {
            setNext(BusinessHandler())
        }
    }

    val request = Request.UserLogin("user", "pass")
    val response = chain.handle(request)
    println(response)
}

相关资料

系列文章导航:


如果这篇文章对你有帮助,欢迎点赞、收藏、分享!有任何问题或建议,欢迎在评论区留言讨论。让我们一起学习,一起成长!

也欢迎访问我的个人主页发现更多宝藏资源