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 抽象类提供了:
- 部分实现:可以有具体方法和抽象方法
- 状态存储:可以有属性和字段
- 构造器:可以有主构造器和次构造器
- 访问控制:完整的可见性修饰符
- 模板方法:定义算法骨架的理想选择
使用原则:
- 当多个类共享状态和共同实现时,使用抽象类
- 当定义纯契约或需要多继承时,使用接口
- 考虑使用组合和委托来避免过深的继承层次
- 在设计 API 时,优先考虑接口以提高灵活性