职责链模式的目的
职责链模式旨在创建一系列顺序处理器。链中的每一个处理程序都可以在任何点终止链的继续传递,这意味着链中只有部分处理程序需要处理数据。此外,还可以根据需求自由组成链的顺序。
从中获得的好处是什么?
- 单一职责:每个处理器只负责一件事。
- 可控的处理顺序。
- 开闭原则:可以添加新的处理程序而不破坏现有代码。
- 处理程序可以根据运行时条件处理数据或将其传递给下一个处理程序。
实现
在实现这个模式时,可能会使用抽象类。但如果可能,最好使用接口。你也可能遇到没有setNext(handler: Handler)方法的实现,而是通过构造函数传递Handler实现。
通常,在实现这个模式时,只有一个处理器会处理数据,其他的则不会。这经常用于UI中。例如,在Compose中,你可能想要将onClick 处理程序lambda在层次结构中向上传递。
示例
计算ATM在某人试图取钱时会提取多少张钞票。如果某人想取58美元,可以给他1张50美元的,1张5美元的,以及3张1美元的钞票,总计58美元。可以通过职责链模式来实现:
出于简化的目的,ATM只支持50美元,5美元和1美元的钞票。
首先创建接口:
interface ATM {
fun withdraw(amount: Int)
fun setNext(atm: ATM)
}
现在是具体的ATM。所有代码都非常相似。
class ATM50Dollars : ATM {
private var nextATM: ATM? = null
override fun withdraw(amount: Int) {
println("提取 ${amount / 50} 张50美元钞票")
nextATM?.withdraw(amount % 50)
}
override fun setNext(atm: ATM) {
nextATM = atm
}
}
class ATM5Dollars : ATM {
private var nextATM: ATM? = null
override fun withdraw(amount: Int) {
println("提取 ${amount / 5} 张5美元钞票")
nextATM?.withdraw(amount % 5)
}
override fun setNext(atm: ATM) {
nextATM = atm
}
}
class ATM1Dollar : ATM {
private var nextATM: ATM? = null
override fun withdraw(amount: Int) {
println("提取 $amount 张1美元钞票")
nextATM?.withdraw(0)
}
override fun setNext(atm: ATM) {
nextATM = atm
}
}
在这种情况下,如果没有取出所有的钱,你可能也想抛出一个错误。给定的对象可能无法处理给定的任务。预防此类情况发生。
现在,请看使用例子:
fun main() {
val atm1: ATM = ATM1Dollar()
val atm50: ATM = ATM50Dollars()
atm50.setNext(atm1)
atm50.withdraw(58) // 1 x 50$ + 8 x 1$
val atm5: ATM = ATM5Dollars()
atm50.setNext(atm5)
atm5.setNext(atm1)
atm50.withdraw(58) // 1 x 50$ + 1 x 5$ + 3 x 1$
atm5.withdraw(58) // 11 x 5$ + 3 x 1$
}
这种模式的可能使您的程序变得更加复杂,但减少了代码的耦合,在需求变更时能快速适配。
该模式与装饰器类似。唯一真正的区别是处理类之一可以返回责任链中的结果。相反,所有组合类都必须处理装饰器中的数据。