2-2-3 快速掌握Kotlin-语言的抽象类学习

21 阅读4分钟

Kotlin 抽象类深入学习

抽象类是 Kotlin 面向对象编程中的重要概念,它介于接口和具体类之间。下面详细讲解抽象类的各个方面:

1. 抽象类基本概念

什么是抽象类

// 抽象类不能实例化,只能被继承
abstract class Animal {
    // 抽象属性 - 没有初始化值
    abstract val name: String
    
    // 抽象方法 - 没有方法体
    abstract fun makeSound()
    
    // 具体方法 - 有默认实现
    fun eat() {
        println("$name 正在吃东西")
    }
    
    // 具体属性 - 有初始化值
    val species: String = "动物"
}

// 子类必须实现所有抽象成员
class Dog : Animal() {
    override val name: String = "狗狗"
    
    override fun makeSound() {
        println("汪汪!")
    }
}

// 编译错误:不能实例化抽象类
// val animal = Animal()  // 错误!

2. 抽象类与接口的对比

// 接口:纯契约,无状态
interface Vehicle {
    fun start()
    fun stop()
    
    // 接口可以有默认实现
    fun honk() = println("嘟嘟!")
}

// 抽象类:可以有状态和部分实现
abstract class AbstractVehicle {
    // 可以有状态(属性带存储)
    var speed: Int = 0
    protected var isRunning: Boolean = false
    
    // 可以有构造函数
    constructor(maxSpeed: Int) {
        println("最大速度: $maxSpeed")
    }
    
    // 抽象方法
    abstract fun start()
    abstract fun stop()
    
    // 具体方法(需要 open 才能被重写)
    open fun accelerate() {
        speed += 10
    }
    
    // final 方法(不能被子类重写)
    final fun currentSpeed(): Int = speed
    
    // 可以有初始化块
    init {
        println("车辆初始化完成")
    }
}

class Car(maxSpeed: Int) : AbstractVehicle(maxSpeed) {
    override fun start() {
        isRunning = true
        println("汽车启动")
    }
    
    override fun stop() {
        isRunning = false
        speed = 0
        println("汽车停止")
    }
    
    // 重写具体方法
    override fun accelerate() {
        super.accelerate()
        println("当前速度: $speed")
    }
}

3. 抽象类的构造函数

// 抽象类可以有主构造器
abstract class Person(val id: Int) {
    abstract val name: String
    abstract fun introduce()
    
    // 可以有次构造器
    constructor() : this(0) {
        println("使用默认ID")
    }
}

// 子类调用父类构造器
class Student(id: Int) : Person(id) {
    override val name: String = "学生"
    
    override fun introduce() {
        println("我是学生,ID: $id")
    }
}

// 使用次构造器
class Teacher : Person() {
    override val name: String = "老师"
    
    override fun introduce() {
        println("我是老师,ID: $id")
    }
}

// 更复杂的继承链
open class Entity(val createdAt: Long)

abstract class UserEntity(createdAt: Long, val username: String) : Entity(createdAt) {
    abstract fun validate(): Boolean
}

class AdminEntity(createdAt: Long, username: String, val level: Int) 
    : UserEntity(createdAt, username) {
    
    override fun validate(): Boolean {
        return username.isNotBlank() && level > 0
    }
    
    init {
        println("管理员实体创建: $username, 级别: $level")
    }
}

4. 抽象属性

abstract class Shape {
    // 抽象属性(必须在子类初始化)
    abstract val area: Double
    abstract val perimeter: Double
    
    // 计算属性(基于抽象属性)
    val isLarge: Boolean
        get() = area > 100
    
    // 带 setter 的抽象属性
    abstract var color: String
        protected set  // 可以限制访问权限
}

class Rectangle(val width: Double, val height: Double) : Shape() {
    override val area: Double
        get() = width * height
    
    override val perimeter: Double
        get() = 2 * (width + height)
    
    override var color: String = "红色"
        set(value) {
            if (value.isNotBlank()) {
                field = value
            }
        }
    
    // 新增属性
    val isSquare: Boolean
        get() = width == height
}

// 使用惰性初始化的抽象属性
abstract class Configuration {
    abstract val configMap: Map<String, Any>
    
    // 在抽象类中提供部分实现
    val appName: String by lazy {
        configMap["appName"] as? String ?: "默认应用"
    }
}

class AppConfig : Configuration() {
    override val configMap: Map<String, Any> by lazy {
        // 延迟加载配置
        loadConfigFromFile()
    }
    
    private fun loadConfigFromFile(): Map<String, Any> {
        // 模拟从文件加载
        return mapOf("appName" to "我的应用", "version" to "1.0")
    }
}

5. 抽象方法

abstract class DataProcessor<T> {
    // 抽象方法
    abstract fun process(data: T): T
    
    // 模板方法模式:定义算法骨架
    fun execute(data: T): T {
        validate(data)
        val processed = process(data)
        log(processed)
        return processed
    }
    
    // 钩子方法(hook method)- 可选重写
    open fun validate(data: T) {
        // 默认验证逻辑
    }
    
    private fun log(data: T) {
        println("处理完成: $data")
    }
    
    // 可以有多个抽象方法
    abstract fun canProcess(data: T): Boolean
}

class StringProcessor : DataProcessor<String>() {
    override fun process(data: String): String {
        return data.uppercase()
    }
    
    override fun validate(data: String) {
        require(data.isNotBlank()) { "数据不能为空" }
    }
    
    override fun canProcess(data: String): Boolean {
        return data.isNotEmpty()
    }
}

6. 抽象类继承层次

// 多层抽象类继承
abstract class Database {
    abstract fun connect()
    abstract fun disconnect()
    
    open fun testConnection(): Boolean {
        connect()
        val connected = isConnected()
        disconnect()
        return connected
    }
    
    abstract fun isConnected(): Boolean
}

abstract class SQLDatabase : Database() {
    abstract val connectionString: String
    
    override fun connect() {
        println("连接到SQL数据库: $connectionString")
    }
    
    override fun disconnect() {
        println("断开SQL数据库连接")
    }
    
    // 新增抽象方法
    abstract fun executeQuery(sql: String): List<Map<String, Any>>
}

class MySQLDatabase(override val connectionString: String) : SQLDatabase() {
    private var connected = false
    
    override fun isConnected(): Boolean = connected
    
    override fun connect() {
        super.connect()
        connected = true
    }
    
    override fun disconnect() {
        super.disconnect()
        connected = false
    }
    
    override fun executeQuery(sql: String): List<Map<String, Any>> {
        println("执行查询: $sql")
        // 模拟返回数据
        return listOf(mapOf("id" to 1, "name" to "Alice"))
    }
    
    // 新增具体方法
    fun getVersion(): String = "MySQL 8.0"
}

7. 抽象类与密封类的结合

// 密封类可以是抽象的
sealed abstract class Result<out T> {
    abstract val timestamp: Long
    
    data class Success<T>(val data: T, override val timestamp: Long) : Result<T>()
    data class Error(val exception: Throwable, override val timestamp: Long) : Result<Nothing>()
    
    abstract class Loading(override val timestamp: Long) : Result<Nothing>() {
        abstract val progress: Float
    }
}

// 继承密封抽象类
class DownloadResult(timestamp: Long) : Result.Loading(timestamp) {
    override val progress: Float
        get() = calculateProgress()
    
    private fun calculateProgress(): Float {
        // 计算下载进度
        return 0.75f
    }
}

fun handleResult(result: Result<String>) {
    when (result) {
        is Result.Success -> println("成功: ${result.data}")
        is Result.Error -> println("错误: ${result.exception}")
        is Result.Loading -> println("加载中: ${result.progress}")
    }
}

8. 抽象类的实用设计模式

模板方法模式

abstract class Game {
    // 模板方法:定义算法骨架
    fun play() {
        initialize()
        startPlay()
        endPlay()
        showScore()
    }
    
    // 具体方法
    private fun initialize() {
        println("游戏初始化完成")
    }
    
    // 抽象方法(由子类实现)
    protected abstract fun startPlay()
    protected abstract fun endPlay()
    
    // 钩子方法(可选重写)
    protected open fun showScore() {
        println("显示默认分数")
    }
}

class Chess : Game() {
    override fun startPlay() {
        println("开始下国际象棋")
    }
    
    override fun endPlay() {
        println("结束国际象棋游戏")
    }
    
    override fun showScore() {
        println("显示国际象棋分数")
    }
}

class Football : Game() {
    override fun startPlay() {
        println("开始踢足球")
    }
    
    override fun endPlay() {
        println("结束足球比赛")
    }
    // 不重写 showScore(),使用默认实现
}

策略模式

abstract class DiscountStrategy {
    abstract fun apply(price: Double): Double
    
    open fun description(): String = "折扣策略"
}

class PercentageDiscount(private val percentage: Double) : DiscountStrategy() {
    init {
        require(percentage in 0.0..100.0) { "折扣比例必须在0-100之间" }
    }
    
    override fun apply(price: Double): Double {
        return price * (1 - percentage / 100)
    }
    
    override fun description(): String {
        return "${percentage}%折扣"
    }
}

class FixedDiscount(private val amount: Double) : DiscountStrategy() {
    override fun apply(price: Double): Double {
        return maxOf(0.0, price - amount)
    }
    
    override fun description(): String {
        return "固定减免$$amount"
    }
}

class ShoppingCart(private var strategy: DiscountStrategy) {
    private var total: Double = 0.0
    
    fun addItem(price: Double) {
        total += price
    }
    
    fun checkout(): Double {
        return strategy.apply(total)
    }
    
    fun changeStrategy(newStrategy: DiscountStrategy) {
        strategy = newStrategy
    }
}

9. 抽象类的扩展

abstract class Repository<T> {
    abstract fun save(item: T)
    abstract fun findById(id: String): T?
    abstract fun findAll(): List<T>
}

// 为抽象类定义扩展函数
fun <T> Repository<T>.saveAll(items: List<T>) {
    items.forEach { save(it) }
}

fun <T> Repository<T>.existsById(id: String): Boolean {
    return findById(id) != null
}

// 使用扩展
abstract class UserRepository : Repository<User>() {
    abstract fun findByEmail(email: String): User?
}

class InMemoryUserRepository : UserRepository() {
    private val storage = mutableMapOf<String, User>()
    
    override fun save(item: User) {
        storage[item.id] = item
    }
    
    override fun findById(id: String): User? = storage[id]
    
    override fun findAll(): List<User> = storage.values.toList()
    
    override fun findByEmail(email: String): User? {
        return storage.values.find { it.email == email }
    }
    
    // 可以使用扩展函数
    fun testExtensions() {
        val users = listOf(User("1", "alice@example.com"))
        saveAll(users)  // 来自扩展函数
        println(existsById("1"))  // 来自扩展函数
    }
}

data class User(val id: String, val email: String)

10. 抽象类的最佳实践

// 1. 合理设计抽象级别
abstract class PaymentProcessor {
    // 只抽象必要的部分
    abstract fun process(amount: Double): PaymentResult
    abstract fun validate(): Boolean
    
    // 提供公共逻辑
    protected fun logPayment(amount: Double) {
        println("处理支付: $$amount")
    }
}

// 2. 使用组合代替多层继承
interface Logger {
    fun log(message: String)
}

interface Validator {
    fun validate(input: String): Boolean
}

abstract class BaseService {
    protected lateinit var logger: Logger
    protected lateinit var validator: Validator
    
    abstract fun execute(): Boolean
}

// 3. 明确访问控制
abstract class SecureComponent {
    // 私有实现细节
    private val secretKey = generateKey()
    
    // 受保护的方法供子类使用
    protected abstract fun encrypt(data: String): String
    
    // 公开接口
    fun processSecure(data: String): String {
        validate(data)
        return encrypt(data)
    }
    
    private fun validate(data: String) {
        require(data.isNotBlank()) { "数据不能为空" }
    }
    
    private fun generateKey(): String = "secret-key"
}

// 4. 提供工厂方法
abstract class Document {
    abstract fun render(): String
    
    companion object {
        // 工厂方法
        fun create(type: String): Document {
            return when (type) {
                "pdf" -> PdfDocument()
                "html" -> HtmlDocument()
                else -> throw IllegalArgumentException("未知文档类型")
            }
        }
    }
}

class PdfDocument : Document() {
    override fun render(): String = "PDF文档"
}

class HtmlDocument : Document() {
    override fun render(): String = "HTML文档"
}

11. 抽象类的测试

// 为抽象类编写测试
abstract class Calculator {
    abstract fun add(a: Int, b: Int): Int
    abstract fun subtract(a: Int, b: Int): Int
    
    open fun multiply(a: Int, b: Int): Int = a * b
}

// 创建测试实现
class TestCalculator : Calculator() {
    override fun add(a: Int, b: Int): Int = a + b
    override fun subtract(a: Int, b: Int): Int = a - b
}

// 或者使用匿名对象进行测试
@Test
fun testCalculator() {
    val calculator = object : Calculator() {
        override fun add(a: Int, b: Int): Int = a + b
        override fun subtract(a: Int, b: Int): Int = a - b
    }
    
    assertEquals(5, calculator.add(2, 3))
    assertEquals(1, calculator.subtract(3, 2))
    assertEquals(6, calculator.multiply(2, 3))
}

12. 何时使用抽象类 vs 接口

场景使用抽象类使用接口
需要存储状态✅ 可以有字段❌ 不能有字段(只能有属性)
需要构造函数✅ 可以有❌ 不能有
需要私有实现✅ 可以有私有成员⚠️ Kotlin 1.7+ 可以有私有方法
多重继承❌ 只能单继承✅ 可以实现多个接口
模板方法模式✅ 非常适合⚠️ 可用,但不如抽象类自然
代码复用✅ 通过继承复用代码✅ 通过组合和委托
版本兼容性⚠️ 修改可能破坏子类✅ 添加默认方法不影响现有实现
// 实际选择示例
// 当需要共享状态和行为时,用抽象类
abstract class BaseActivity {
    protected val context: Context = ...
    private var isDestroyed = false
    
    abstract fun onCreate()
    
    open fun onDestroy() {
        isDestroyed = true
    }
}

// 当需要定义契约时,用接口
interface ClickListener {
    fun onClick()
    fun onLongClick(): Boolean = false  // 可选实现
}

// 结合使用
class MyActivity : BaseActivity(), ClickListener {
    override fun onCreate() { ... }
    override fun onClick() { ... }
    // 可以不重写 onLongClick()
}

总结

Kotlin 抽象类提供了:

  1. 部分实现:可以有具体方法和抽象方法
  2. 状态存储:可以有属性和字段
  3. 构造器:可以有主构造器和次构造器
  4. 访问控制:完整的可见性修饰符
  5. 模板方法:定义算法骨架的理想选择

使用原则

  • 当多个类共享状态和共同实现时,使用抽象类
  • 当定义纯契约或需要多继承时,使用接口
  • 考虑使用组合委托来避免过深的继承层次
  • 在设计 API 时,优先考虑接口以提高灵活性