Kotlin 面向对象
面向对象编程(OOP)是现代软件开发的核心范式。Kotlin 作为一门现代语言,在支持传统 OOP 特性的同时,引入了许多改进和简化。本章将深入介绍类、对象、继承、接口等核心概念,并探讨 Kotlin 特有的面向对象特性。
类与对象
类的定义
类是对象的蓝图,定义了对象的属性和行为。Kotlin 的类定义语法简洁明了:
// 基本类定义
class Person {
// 属性(成员变量)
var name: String = ""
var age: Int = 0
// 方法(成员函数)
fun sayHello() {
println("你好,我是 $name,今年 $age 岁")
}
fun isAdult(): Boolean = age >= 18
}
// 使用类创建对象
fun main() {
// 创建实例
val person = Person()
// 设置属性
person.name = "张三"
person.age = 25
// 调用方法
person.sayHello() // 你好,我是 张三,今年 25 岁
println(person.isAdult()) // true
}
主构造函数
Kotlin 将构造函数分为主构造函数和次构造函数。主构造函数在类头中声明,是最简洁的构造方式:
// 主构造函数:在类名后声明
class Person(val name: String, var age: Int) {
// val/var 参数自动成为属性
fun introduce() = "我是 $name,$age 岁"
}
fun main() {
val person = Person("李四", 30)
println(person.introduce()) // 我是 李四,30 岁
person.age = 31 // var 属性可修改
// person.name = "王五" // val 属性不可修改
}
主构造函数参数的 val 与 var 区别:
val:创建只读属性,只能在构造时赋值var:创建可变属性,可以后续修改- 无修饰符:仅作为构造参数,不成为属性
class Example(
val readOnly: String, // 只读属性
var mutable: Int, // 可变属性
temporary: String // 仅构造参数,不成为属性
) {
fun print() {
println(readOnly) // 可访问
println(mutable) // 可访问
// println(temporary) // 编译错误:无法访问
}
}
init 初始化块
init 块在类实例化时执行,用于执行初始化逻辑或验证参数:
class Person(val name: String, val age: Int) {
// 初始化块:在主构造函数后执行
init {
// 参数验证
require(name.isNotEmpty()) { "姓名不能为空" }
require(age >= 0) { "年龄不能为负数" }
require(age <= 150) { "年龄不合理" }
println("创建 Person: $name, $age 岁")
}
// 可以有多个 init 块,按声明顺序执行
init {
println("初始化完成")
}
}
fun main() {
val person = Person("张三", 25)
// Person("张三", -1) // 抛出 IllegalArgumentException
}
次构造函数
使用 constructor 关键字定义次构造函数,必须委托给主构造函数:
class User(val id: Int, val name: String, val email: String) {
// 次构造函数:必须调用主构造函数
constructor(id: Int, name: String) : this(id, name, "$name@example.com") {
println("使用默认邮箱创建用户")
}
// 另一个次构造函数
constructor(id: Int) : this(id, "User$id", "user$id@example.com") {
println("使用默认信息创建用户")
}
fun info() = "User($id, $name, $email)"
}
fun main() {
val u1 = User(1, "张三", "[email protected]")
println(u1.info()) // User(1, 张三, [email protected])
val u2 = User(2, "李四")
println(u2.info()) // User(2, 李四, 李四@example.com)
val u3 = User(3)
println(u3.info()) // User(3, User3, [email protected])
}
设计建议:优先使用默认参数而非次构造函数:
// 推荐:使用默认参数
class UserBetter(
val id: Int,
val name: String = "User$id",
val email: String = "$name@example.com"
)
fun main() {
val u1 = UserBetter(1, "张三", "[email protected]")
val u2 = UserBetter(2, "李四")
val u3 = UserBetter(3)
}
属性
属性的基本概念
Kotlin 的属性远比 Java 的字段强大,它自动生成 getter 和 setter(对于 var):
class Person {
// var 属性:自动生成 getter 和 setter
var name: String = "Unknown"
// val 属性:只生成 getter
val id: Int = (1..10000).random()
}
fun main() {
val person = Person()
println(person.name) // 调用 getter
person.name = "张三" // 调用 setter
println(person.id) // 调用 getter
// person.id = 2 // 编译错误:val 不可重新赋值
}
自定义 getter 和 setter
class Rectangle(val width: Int, val height: Int) {
// 计算属性:自定义 getter
val area: Int
get() = width * height
// 带逻辑的 setter
var description: String = "矩形"
get() = "$field (宽: $width, 高: $height)"
set(value) {
field = value.uppercase() // field 是幕后字段
}
// 可观察属性
var count: Int = 0
set(value) {
println("count 从 $field 变为 $value")
field = value
}
}
fun main() {
val rect = Rectangle(10, 20)
println("面积: ${rect.area}") // 200
println(rect.description) // 矩形 (宽: 10, 高: 20)
rect.count = 5 // count 从 0 变为 5
rect.count = 10 // count 从 5 变为 10
}
幕后字段 field:在 getter/setter 中,field 标识符引用属性的幕后存储。只在需要时生成,避免递归调用。
class Example {
// 正确:使用 field
var value: Int = 0
set(newValue) {
if (newValue >= 0) field = newValue
}
// 错误:会导致无限递归
// var wrong: Int = 0
// set(newValue) {
// wrong = newValue // 调用 setter,无限循环!
// }
}
延迟初始化
当属性无法在构造时初始化时,可以使用延迟初始化:
class Service {
// lateinit:用于 var,稍后初始化
lateinit var database: Database
fun init() {
database = Database.connect()
}
fun query(): String {
// 检查是否已初始化
if (::database.isInitialized) {
return database.query()
}
return "数据库未初始化"
}
}
class Database {
companion object {
fun connect() = Database()
}
fun query() = "查询结果"
}
// lazy:用于 val,首次访问时初始化
class Config {
// 惰性初始化:线程安全
val settings: Map<String, String> by lazy {
println("加载配置...")
mapOf("host" to "localhost", "port" to "8080")
}
// 惰性初始化:非线程安全(性能更好)
val cache: MutableList<String> by lazy(LazyThreadSafetyMode.NONE) {
mutableListOf()
}
}
fun main() {
val config = Config()
println("创建 Config 完成")
println(config.settings) // 此时才初始化
}
lateinit vs lazy 选择:
| 特性 | lateinit | lazy |
|---|---|---|
| 适用类型 | var | val |
| 初始化时机 | 手动控制 | 首次访问 |
| 线程安全 | 无保证 | 默认安全 |
| 可空性 | 非空 | 任意 |
| 检查初始化 | ::property.isInitialized | 自动 |
可见性修饰符
Kotlin 提供四种可见性修饰符,控制类、属性、方法的访问级别:
// 可见性修饰符示例
class VisibilityExample {
// public(默认):随处可见
var publicProp: String = "public"
// private:仅类内可见
private var privateProp: String = "private"
// protected:类内及子类可见
protected var protectedProp: String = "protected"
// internal:模块内可见
internal var internalProp: String = "internal"
// 私有方法
private fun privateMethod() = "私有方法"
// 公开方法可以访问私有成员
fun accessPrivate() = privateProp
// 嵌套类可以访问外部类的私有成员
class Nested {
fun accessOuter(outer: VisibilityExample) {
// println(outer.privateProp) // 编译错误
println(outer.publicProp)
}
}
}
// 继承示例
class Child : VisibilityExample() {
fun accessProtected() {
println(protectedProp) // 可以访问
// println(privateProp) // 编译错误
}
}
// 顶层可见性
private class PrivateClass // 仅本文件可见
internal class InternalClass // 模块内可见
可见性总结:
| 修饰符 | 类成员 | 顶层声明 |
|---|---|---|
public | 随处可见 | 随处可见 |
private | 仅类内可见 | 仅文件内可见 |
protected | 类及子类可见 | 不适用 |
internal | 模块内可见 | 模块内可见 |
继承
类的继承
Kotlin 的类默认是 final 的,必须使用 open 关键字才能被继承:
// 基类必须用 open 修饰
open class Animal(val name: String) {
// 可被覆盖的方法也要用 open
open fun makeSound() {
println("$name 发出声音")
}
// 不可覆盖的方法
fun sleep() {
println("$name 正在睡觉")
}
}
// 子类继承
class Dog(name: String, val breed: String) : Animal(name) {
// 覆盖方法
override fun makeSound() {
println("$name ($breed) 汪汪叫")
}
// 子类特有方法
fun fetch() {
println("$name 去捡球")
}
}
class Cat(name: String) : Animal(name) {
override fun makeSound() {
println("$name 喵喵叫")
}
}
fun main() {
val dog = Dog("旺财", "拉布拉多")
dog.makeSound() // 旺财 (拉布拉多) 汪汪叫
dog.sleep() // 旺财 正在睡觉
// 多态
val animals: List<Animal> = listOf(Dog("小黑", "德牧"), Cat("小花"))
animals.forEach { it.makeSound() }
}
调用父类方法
使用 super 关键字调用父类方法:
open class Vehicle(val brand: String) {
open fun start() {
println("$brand 启动")
}
}
class Car(brand: String, val model: String) : Vehicle(brand) {
override fun start() {
super.start() // 调用父类方法
println("$brand $model 准备就绪")
}
fun showInfo() {
println("品牌: ${super.brand}") // 访问父类属性
}
}
fun main() {
val car = Car("Toyota", "Camry")
car.start()
// Toyota 启动
// Toyota Camry 准备就绪
}
多态与类型转换
open class Shape {
open fun draw() = "绘制形状"
open fun area(): Double = 0.0
}
class Circle(val radius: Double) : Shape() {
override fun draw() = "绘制圆形(半径 $radius)"
override fun area() = Math.PI * radius * radius
fun circumference() = 2 * Math.PI * radius
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun draw() = "绘制矩形(${width}x${height})"
override fun area() = width * height
}
fun main() {
// 多态:父类引用指向子类对象
val shapes: List<Shape> = listOf(
Circle(5.0),
Rectangle(4.0, 3.0),
Circle(2.5)
)
shapes.forEach { shape ->
println("${shape.draw()},面积: ${shape.area()}")
// 智能类型转换
if (shape is Circle) {
println(" 周长: ${shape.circumference()}")
}
}
// 安全类型转换
val circle = shapes[0] as? Circle
println("是圆形吗?${circle != null}")
// 不安全转换(可能抛出 ClassCastException)
// val rect = shapes[0] as Rectangle // 运行时错误
}
接口
接口定义了行为的契约,Kotlin 接口可以包含抽象方法、默认实现和属性。
接口定义与实现
// 定义接口
interface Drawable {
// 抽象属性
val color: String
// 抽象方法
fun draw()
// 默认实现
fun description() = "这是一个可绘制的对象,颜色: $color"
// 可以有默认实现的方法
fun reset() {
println("重置绘制状态")
}
}
interface Clickable {
fun click()
fun doubleClick() {
println("双击")
}
}
// 实现接口
class Button(override val color: String, val text: String) : Drawable, Clickable {
override fun draw() {
println("绘制 $color 按钮: $text")
}
override fun click() {
println("点击按钮: $text")
}
// 可以覆盖默认实现
override fun doubleClick() {
println("按钮 $text 被双击")
}
}
fun main() {
val button = Button("蓝色", "确定")
button.draw() // 绘制 蓝色 按钮: 确定
button.click() // 点击按钮: 确定
button.description() // 这是一个可绘制的对象,颜色: 蓝色
}
接口继承与冲突解决
interface A {
fun foo() { println("A.foo") }
fun bar()
}
interface B {
fun foo() { println("B.foo") }
fun bar() { println("B.bar") }
}
// 实现多个接口
class C : A, B {
// 必须覆盖冲突的方法
override fun foo() {
super<A>.foo() // 调用 A 的实现
super<B>.foo() // 调用 B 的实现
println("C.foo")
}
override fun bar() {
super<B>.bar() // 调用 B 的实现
}
}
fun main() {
val c = C()
c.foo()
// A.foo
// B.foo
// C.foo
}
接口 vs 抽象类
| 特性 | 接口 | 抽象类 |
|---|---|---|
| 多继承 | 可以实现多个 | 只能继承一个 |
| 状态 | 不能有状态 | 可以有成员变量 |
| 构造函数 | 无 | 有 |
| 属性 | 只能是抽象或有访问器 | 可以有具体属性 |
| 使用场景 | 定义行为契约 | 共享实现和状态 |
// 抽象类:共享状态和实现
abstract class BaseViewModel {
protected var isLoading = false
abstract fun load()
fun showLoading() {
isLoading = true
println("显示加载中...")
}
fun hideLoading() {
isLoading = false
println("隐藏加载")
}
}
// 接口:定义能力
interface Refreshable {
fun refresh()
}
interface Searchable {
fun search(query: String)
}
// 结合使用
class UserViewModel : BaseViewModel(), Refreshable, Searchable {
override fun load() {
showLoading()
println("加载用户数据")
hideLoading()
}
override fun refresh() {
println("刷新用户数据")
}
override fun search(query: String) {
println("搜索用户: $query")
}
}
数据类
数据类专门用于存储数据,自动生成 equals()、hashCode()、toString()、copy() 等方法:
// 定义数据类
data class User(
val id: Int,
val name: String,
val email: String,
val age: Int = 0 // 默认参数
)
fun main() {
val u1 = User(1, "张三", "[email protected]", 25)
val u2 = User(1, "张三", "[email protected]", 25)
val u3 = User(2, "李四", "[email protected]")
// 自动生成的 toString()
println(u1) // User(id=1, name=张三, [email protected], age=25)
// 自动生成的 equals():比较所有属性
println(u1 == u2) // true
println(u1 == u3) // false
// 自动生成的 hashCode()
println(u1.hashCode() == u2.hashCode()) // true
// copy():复制并修改部分属性
val u4 = u1.copy(name = "王五")
println(u4) // User(id=1, name=王五, [email protected], age=25)
// 解构声明
val (id, name, email, age) = u1
println("ID: $id, 姓名: $name, 邮箱: $email, 年龄: $age")
// 部分解构
val (userId, userName) = u1
println("$userId: $userName")
}
数据类的限制
// 数据类必须满足:
// 1. 主构造函数至少有一个参数
// 2. 主构造函数参数必须标记为 val 或 var
// 3. 不能是 abstract、open、sealed、inner
// 错误示例:
// data class Empty() // 可以,但没有意义
// 数据类可以有额外的方法和属性
data class Product(
val id: Int,
val name: String,
val price: Double
) {
// 计算属性
val formattedPrice: String
get() = "¥${String.format("%.2f", price)}"
// 额外方法
fun isExpensive() = price > 1000
// 可以覆盖自动生成的方法
override fun toString(): String {
return "商品[$id]: $name - $formattedPrice"
}
}
fun main() {
val product = Product(1, "手机", 2999.0)
println(product.formattedPrice) // ¥2999.00
println(product.isExpensive()) // true
println(product) // 商品[1]: 手机 - ¥2999.00
}
密封类
密封类限制继承层次,只能在同一文件中定义子类。配合 when 表达式实现穷尽检查:
// 密封类:受限的类层次结构
sealed class Result {
// 子类可以是 data class、object 或普通 class
data class Success(val data: String) : Result()
data class Error(val code: Int, val message: String) : Result()
object Loading : Result()
object Empty : Result()
}
// 处理结果(when 必须穷尽所有情况)
fun handleResult(result: Result): String = when (result) {
is Result.Success -> "成功: ${result.data}"
is Result.Error -> "错误 ${result.code}: ${result.message}"
Result.Loading -> "加载中..."
Result.Empty -> "无数据"
// 不需要 else 分支,编译器确保覆盖所有情况
}
// 密封接口(Kotlin 1.5+)
sealed interface UiState {
object Idle : UiState
object Loading : UiState
data class Success(val data: Any) : UiState
data class Error(val throwable: Throwable) : UiState
}
fun main() {
val results = listOf(
Result.Success("用户数据"),
Result.Error(404, "未找到"),
Result.Loading,
Result.Empty
)
results.forEach { println(handleResult(it)) }
}
密封类的实际应用
// 网络请求状态
sealed class NetworkState<out T> {
object Idle : NetworkState<Nothing>()
object Loading : NetworkState<Nothing>()
data class Success<T>(val data: T) : NetworkState<T>()
data class Error(val exception: Throwable) : NetworkState<Nothing>()
}
// UI 事件
sealed class UiEvent {
data class ShowToast(val message: String) : UiEvent()
data class Navigate(val route: String) : UiEvent()
data class ShowDialog(val title: String, val message: String) : UiEvent()
object PopBackStack : UiEvent()
}
// 支付方式
sealed class PaymentMethod {
data class CreditCard(val number: String, val cvv: String) : PaymentMethod()
data class PayPal(val email: String) : PaymentMethod()
object Cash : PaymentMethod()
fun process(amount: Double): String = when (this) {
is CreditCard -> "信用卡支付 $$amount"
is PayPal -> "PayPal 支付 $$amount"
Cash -> "现金支付 ¥$amount"
}
}
fun main() {
val payment = PaymentMethod.CreditCard("****1234", "123")
println(payment.process(99.99))
}
枚举类
枚举类定义一组命名的常量值:
// 基本枚举
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
// 带属性的枚举
enum class Color(val rgb: Int, val chineseName: String) {
RED(0xFF0000, "红色"),
GREEN(0x00FF00, "绿色"),
BLUE(0x0000FF, "蓝色");
fun hex() = "#${Integer.toHexString(rgb)}"
}
// 带方法的枚举
enum class Planet(val mass: Double, val radius: Double) {
EARTH(5.976e24, 6.37814e3),
MARS(6.421e23, 3.3972e3),
JUPITER(1.9e27, 7.1492e4);
// 计算表面重力
fun surfaceGravity() = 6.67300E-11 * mass / (radius * radius)
fun surfaceWeight(otherMass: Double) = otherMass * surfaceGravity()
override fun toString() = name.lowercase().replaceFirstChar { it.uppercase() }
}
fun main() {
// 遍历枚举
Direction.entries.forEach { println(it) }
// 获取枚举值
val color = Color.RED
println("${color.chineseName}: ${color.hex()}") // 红色: #ff0000
// 枚举在 when 中使用
val dir = Direction.NORTH
val description = when (dir) {
Direction.NORTH -> "北方"
Direction.SOUTH -> "南方"
Direction.EAST -> "东方"
Direction.WEST -> "西方"
}
println(description)
// 行星计算
val earthWeight = 75.0
println("地球表面重力: ${Planet.EARTH.surfaceGravity()}")
println("火星上的重量: ${Planet.MARS.surfaceWeight(earthWeight)}")
}
枚举与接口
interface Printable {
fun print(): String
}
enum class Status : Printable {
PENDING {
override fun print() = "待处理"
},
PROCESSING {
override fun print() = "处理中"
},
COMPLETED {
override fun print() = "已完成"
},
FAILED {
override fun print() = "失败"
};
// 枚举常量可以覆盖该方法
override fun print() = name
}
fun main() {
Status.entries.forEach {
println("${it.name}: ${it.print()}")
}
}
对象声明与伴生对象
单例对象
使用 object 关键字声明单例,整个程序只有一个实例:
// 单例对象
object Database {
private val connection = mutableMapOf<String, String>()
val url: String = "jdbc:mysql://localhost:3306/mydb"
fun connect() {
println("连接数据库: $url")
}
fun query(sql: String): List<Map<String, Any>> {
println("执行查询: $sql")
return emptyList()
}
fun close() {
println("关闭连接")
}
}
fun main() {
// 直接使用,无需创建实例
Database.connect()
Database.query("SELECT * FROM users")
// 类似静态成员的访问方式
println(Database.url)
}
伴生对象
伴生对象是类内部的单例,可以访问类的私有成员,类似静态成员:
class User private constructor(val name: String) {
companion object {
private var count = 0
// 常量
const val TAG = "User"
// 工厂方法
fun create(name: String): User {
count++
return User(name)
}
fun createDefault(): User = User("Guest")
// 可以实现接口
fun count() = count
}
fun show() = "User: $name (总共创建 $count 个)"
}
fun main() {
// 通过伴生对象调用
val u1 = User.create("张三")
val u2 = User.createDefault()
println(u1.show()) // User: 张三 (总共创建 2 个)
println(User.TAG) // User
println("共创建 ${User.count()} 个用户")
}
伴生对象实现接口
interface Factory<T> {
fun create(): T
}
class Product(val id: Int, val name: String) {
companion object : Factory<Product> {
private var nextId = 0
override fun create(): Product {
return Product(nextId++, "Product-$nextId")
}
fun createWithName(name: String) = Product(nextId++, name)
}
}
fun main() {
// 作为接口使用
val factory: Factory<Product> = Product
val product = factory.create()
println(product)
}
嵌套类与内部类
嵌套类(静态内部类)
默认情况下,Kotlin 的嵌套类是静态的,不持有外部类引用:
class Outer {
private val outerValue = 10
// 嵌套类(默认 static)
class Nested {
fun nestedMethod() = "嵌套类方法"
// 不能访问 outerValue
}
}
fun main() {
// 直接创建嵌套类实例
val nested = Outer.Nested()
println(nested.nestedMethod())
}
内部类
使用 inner 关键字声明内部类,持有外部类引用:
class Outer {
private val outerValue = 10
fun showOuter() = "外部类: outerValue = $outerValue"
// 内部类:可以访问外部类成员
inner class Inner {
private val innerValue = 20
fun innerMethod() = "内部类: innerValue = $innerValue, outerValue = $outerValue"
fun accessOuter() = this@Outer.showOuter() // 访问外部类方法
}
}
fun main() {
val outer = Outer()
// 必须通过外部类实例创建内部类
val inner = outer.Inner()
println(inner.innerMethod())
println(inner.accessOuter())
}
匿名内部类
使用 object 表达式创建匿名内部类:
interface OnClickListener {
fun onClick()
fun onLongClick() {}
}
class Button {
fun setOnClickListener(listener: OnClickListener) {
listener.onClick()
}
}
fun main() {
val button = Button()
// 匿名内部类
button.setOnClickListener(object : OnClickListener {
override fun onClick() {
println("按钮被点击")
}
override fun onLongClick() {
println("按钮被长按")
}
})
// 使用 Lambda(如果接口是函数式接口)
// button.setOnClickListener { println("点击") }
}
类型别名
使用 typealias 为类型创建别名,提高代码可读性:
// 类型别名
typealias UserMap = Map<String, MutableList<User>>
typealias Predicate<T> = (T) -> Boolean
typealias ClickHandler = (Int, Int) -> Unit
// 扩展函数别名
typealias Validator = String.() -> Boolean
fun main() {
// 使用别名
val users: UserMap = mutableMapOf(
"admin" to mutableListOf(User(1, "管理员", "[email protected]"))
)
// 函数类型别名
val isAdult: Predicate<User> = { it.age >= 18 }
val handler: ClickHandler = { x, y -> println("点击 ($x, $y)") }
// 扩展函数别名使用
val isValidEmail: Validator = { contains("@") && contains(".") }
"[email protected]".isValidEmail()
}
设计模式实践
单例模式
Kotlin 的 object 声明天然实现单例模式:
// 方式一:object 声明(推荐)
object Singleton {
fun doSomething() = "单例操作"
}
// 方式二:伴生对象 + 私有构造函数
class SingletonPrivate private constructor() {
companion object {
val instance: SingletonPrivate by lazy { SingletonPrivate() }
}
fun doSomething() = "懒加载单例"
}
// 方式三:双重检查锁(多线程安全)
class SingletonThreadSafe private constructor() {
companion object {
@Volatile
private var instance: SingletonThreadSafe? = null
fun getInstance(): SingletonThreadSafe {
return instance ?: synchronized(this) {
instance ?: SingletonThreadSafe().also { instance = it }
}
}
}
}
工厂模式
// 工厂方法模式
interface Shape {
fun draw()
}
class Circle(val radius: Double) : Shape {
override fun draw() = println("绘制圆形,半径 $radius")
}
class Square(val side: Double) : Shape {
override fun draw() = println("绘制正方形,边长 $side")
}
// 伴生对象工厂
class ShapeFactory {
companion object {
fun createCircle(radius: Double) = Circle(radius)
fun createSquare(side: Double) = Square(side)
// 根据 type 创建
fun create(type: String, size: Double): Shape = when (type) {
"circle" -> Circle(size)
"square" -> Square(size)
else -> throw IllegalArgumentException("未知类型: $type")
}
}
}
fun main() {
val circle = ShapeFactory.createCircle(5.0)
val square = ShapeFactory.create("square", 4.0)
circle.draw()
square.draw()
}
建造者模式
Kotlin 使用默认参数和 DSL 风格实现建造者模式:
// 方式一:默认参数(推荐)
data class HttpRequest(
val url: String,
val method: String = "GET",
val headers: Map<String, String> = emptyMap(),
val body: String? = null,
val timeout: Int = 30000
)
fun main() {
val request = HttpRequest(
url = "https://api.example.com",
method = "POST",
headers = mapOf("Content-Type" to "application/json"),
body = """{"name": "test"}"""
)
}
// 方式二:DSL 风格构建器
class HttpRequestBuilder {
var url: String = ""
var method: String = "GET"
private val headers = mutableMapOf<String, String>()
var body: String? = null
var timeout: Int = 30000
fun header(name: String, value: String) {
headers[name] = value
}
fun build() = HttpRequest(url, method, headers.toMap(), body, timeout)
}
fun httpRequest(block: HttpRequestBuilder.() -> Unit): HttpRequest {
return HttpRequestBuilder().apply(block).build()
}
// 使用 DSL 创建
val dslRequest = httpRequest {
url = "https://api.example.com"
method = "POST"
header("Content-Type", "application/json")
body = """{"name": "test"}"""
}
策略模式
// 策略接口
interface DiscountStrategy {
fun calculate(price: Double): Double
}
// 具体策略
class NoDiscount : DiscountStrategy {
override fun calculate(price: Double) = price
}
class PercentageDiscount(private val percent: Double) : DiscountStrategy {
override fun calculate(price: Double) = price * (1 - percent / 100)
}
class FixedDiscount(private val amount: Double) : DiscountStrategy {
override fun calculate(price: Double) = maxOf(0.0, price - amount)
}
// 上下文
class ShoppingCart(private var strategy: DiscountStrategy = NoDiscount()) {
private val items = mutableListOf<Pair<String, Double>>()
fun addItem(name: String, price: Double) {
items.add(name to price)
}
fun setStrategy(newStrategy: DiscountStrategy) {
strategy = newStrategy
}
fun checkout(): Double {
val total = items.sumOf { it.second }
return strategy.calculate(total)
}
}
fun main() {
val cart = ShoppingCart()
cart.addItem("商品A", 100.0)
cart.addItem("商品B", 200.0)
println("原价: ${cart.checkout()}") // 300.0
cart.setStrategy(PercentageDiscount(10.0))
println("9折: ${cart.checkout()}") // 270.0
cart.setStrategy(FixedDiscount(50.0))
println("减50: ${cart.checkout()}") // 250.0
}
观察者模式
// 观察者接口
interface Observer<T> {
fun onUpdate(data: T)
}
// 被观察者
class Observable<T> {
private val observers = mutableListOf<Observer<T>>()
fun subscribe(observer: Observer<T>) {
observers.add(observer)
}
fun unsubscribe(observer: Observer<T>) {
observers.remove(observer)
}
fun notify(data: T) {
observers.forEach { it.onUpdate(data) }
}
}
// 实际应用:新闻发布
class NewsAgency : Observable<String>() {
fun publish(news: String) {
println("发布新闻: $news")
notify(news)
}
}
class NewsReader(val name: String) : Observer<String> {
override fun onUpdate(data: String) {
println("$name 收到新闻: $data")
}
}
fun main() {
val agency = NewsAgency()
val reader1 = NewsReader("张三")
val reader2 = NewsReader("李四")
agency.subscribe(reader1)
agency.subscribe(reader2)
agency.publish("Kotlin 2.0 发布!")
}
小结
本章我们全面学习了 Kotlin 面向对象编程:
- 类与对象:主/次构造函数、属性、初始化块
- 继承:open 类、覆盖方法、多态
- 接口:抽象方法、默认实现、多继承
- 数据类:自动生成 equals、hashCode、toString、copy
- 密封类:受限继承、穷尽检查
- 枚举类:命名常量、带属性的枚举
- 对象与伴生对象:单例模式、静态成员
- 嵌套类与内部类:静态嵌套、内部引用
- 设计模式:单例、工厂、建造者、策略、观察者
Kotlin 的面向对象特性既保留了 Java 的优点,又引入了许多现代化的改进,让代码更加简洁、安全、表达力强。
练习
- 创建一个
BankAccount类,包含账户余额、存款、取款方法,并实现线程安全 - 使用密封类实现一个简单的状态机(如订单状态流转)
- 使用数据类和密封类实现一个网络请求结果封装
- 实现一个通用的 Repository 模式,支持不同的数据源
- 使用策略模式实现不同的排序算法