引言:那个让我重构的"万能类"
还记得刚入行时,我写过一个"万能"的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: 为什么要用委托而不是继承?
继承的问题:
- 紧耦合,子类依赖父类实现
- 违反单一职责原则(为了复用功能而继承)
- 难以改变行为(编译时确定)
委托的优势:
- 松耦合,可以运行时替换
- 符合单一职责原则
- 更灵活的组合
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)
}
相关资料
系列文章导航:
- 👉 上一篇: 集合框架:从Java的冗长到函数式编程的优雅
如果这篇文章对你有帮助,欢迎点赞、收藏、分享!有任何问题或建议,欢迎在评论区留言讨论。让我们一起学习,一起成长!
也欢迎访问我的个人主页发现更多宝藏资源