Scala 设计模式 责任链

简介

责任链模式(Chain of Responsibility)是行为型设计模式之一
其将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象

  • 纯:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。
  • 不纯:允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。

利用 trait 实现纯责任链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
trait L {
def p(x: Int): Int = throw new IllegalStateException("aa")
}

trait L1 extends L {
override def p(x: Int): Int = {
println("enter l1")
if (x == 1) {
x
} else {
super.p(x)
}
}
}

trait L2 extends L {
override def p(x: Int): Int = {
println("enter l2")
if (x == 2) {
x
} else {
super.p(x)
}
}
}

object C extends L1 with L2

C.p(1)
println("--------")
C.p(2)
println("--------")
C.p(3)

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enter l2
enter l1
--------
enter l2
--------
enter l2
enter l1
java.lang.IllegalStateException: aa
at L.p(<pastie>:12)
at L.p$(<pastie>:12)
at C$.$line6$$read$L1$$super$p(<pastie>:37)
at L1.p(<pastie>:21)
at L1.p$(<pastie>:16)
at C$.$line6$$read$L2$$super$p(<pastie>:37)
at L2.p(<pastie>:32)
at L2.p$(<pastie>:27)
at C$.p(<pastie>:37)
... 37 elided

由输出信息可以看出执行顺序是 L2 -> L1

当条件 x = 1 时,先走 L2 不满足条件,去 L1 处理
当条件 x = 2 时,先走 L2 满足条件处理完结束
当条件 x = 3 时,先走 L2, 再到 L1, 都不满足, 在 trait 中 处理 抛出异常

利用 Scala 偏函数 实现责任链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val b1: PartialFunction[String, String] = {
case o => s"$o-b1"
}

val b2: PartialFunction[String, String] = {
case o => s"$o-b2"
}

val b3: PartialFunction[String, String] = {
case o => s"$o-b3"
}

val andthen: String => String = b1 andThen b2 andThen b3
val orelse: String => String = b1 orElse b2 orElse b3

println(andthen("1"))
println(orelse("1"))

由输出信息可以看出 andthen 是不纯责任链,orelse 是纯责任链

1
2
andthen-b1-b2-b3
orelse-b1