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

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

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

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

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

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

kotlin 复制代码
// 正确做法:基于接口的设计
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):定义契约

什么是接口

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

kotlin 复制代码
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")
    }
}

接口可以包含什么

kotlin 复制代码
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支持实现多个接口,这是实现组合优于继承的重要方式:

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")
    }
}

解决冲突

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

kotlin 复制代码
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):共享实现

什么是抽象类

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

kotlin 复制代码
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 可以是任意
使用场景 定义行为契约 定义共同实现
kotlin 复制代码
// 接口:不能有状态
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
    }
}

模板方法模式

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

kotlin 复制代码
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的核心特性,允许用父类型引用指向子类型对象,运行时根据实际类型执行相应的方法。

kotlin 复制代码
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!

多态的类型

1. 方法多态(Method Polymorphism)

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

kotlin 复制代码
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)

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

kotlin 复制代码
// 泛型函数:适用于任何类型
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

多态的优势

kotlin 复制代码
// 不使用多态:代码冗长,难以扩展
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的特色功能,用于表示受限的类层次,所有子类必须在同一文件中定义。

基本用法

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类

特性 enum sealed class
实例数量 固定,编译时确定 可以有多个实例
携带数据 每个常量相同类型 每个子类可以不同
继承 不能有子类 可以有子类
使用场景 简单枚举 复杂的状态/结果
kotlin 复制代码
// 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()
}

实战:状态管理

kotlin 复制代码
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原生支持委托模式,无需手动编写转发代码:

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())

委托的优势

kotlin 复制代码
// 示例:添加日志功能
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"关系时(如带日志的打印机)

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

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

kotlin 复制代码
// 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: 什么时候用接口,什么时候用抽象类?

决策树

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

具体场景

kotlin 复制代码
// ✅ 接口:定义行为契约
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有什么区别?

特性 enum sealed class
实例化 编译时固定 可以有多个实例
数据类型 所有常量相同 每个子类可以不同
继承 不能继承 可以有复杂继承
构造参数 所有常量相同 每个子类可以不同
kotlin 复制代码
// 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. 更灵活的组合
kotlin 复制代码
// ❌ 继承:紧耦合
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)**实现多态:

kotlin 复制代码
// 编译后的虚方法表
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:实现图形绘制系统

kotlin 复制代码
// 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:实现可扩展的日志系统

kotlin 复制代码
// 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:实现职责链模式

kotlin 复制代码
// 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)
}

相关资料

系列文章导航:


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

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

相关推荐
·云扬·2 小时前
ClickHouse数据备份与恢复实战:从基础操作到工具应用
android·java·clickhouse
消失的旧时光-19432 小时前
Android + Flutter 混合架构全景图:从接入到系统的完整方法论
android·flutter
MengFly_2 小时前
Compose案例 — Android 调用系统相机拍照
android·kotlin·compose
tangweiguo030519872 小时前
如何优雅地在Android中集成第三方.so库并封装自定义JNI层
android
游戏开发爱好者82 小时前
如何在 Windows 环境下测试 iOS App,实时日志,CPU监控
android·ios·小程序·https·uni-app·iphone·webview
似霰2 小时前
AIDL Hal 开发笔记1----AIDL HAL 整体架构
android·framework·hal
zh_xuan2 小时前
kotlin数据类用法
开发语言·kotlin
我命由我123453 小时前
Android 开发 - FragmentPagerAdapter、Pair、ClipboardManager、PopupWindow
android·java·java-ee·kotlin·android studio·android-studio·android runtime
摇滚侠3 小时前
尚硅谷新版 Maven 教程(高效入门 Maven,上手又快又稳),配置 Maven,笔记 6、7
android·笔记·maven