参考链接
装饰器模式
装饰器模式又名包装模式,来以对客户透明的方式(客户端并不觉得修饰前后的区别)扩展对象的功能,是继承关系的一种替代方案。

在装饰模式中的角色有:
- 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| interface CanBeWorn{
void worn();
}
class UnderWear implements CanBeWorn{
@Override
public void worn() {
System.out.print("穿内衣");
}
}
/**
* 装饰器模式的核心
* 它的子类都可以代理执行注入类的worn()方法
*/
class Mother implements CanBeWorn{
private CanBeWorn canBeWorn;
public Mother(CanBeWorn canBeWorn){
this.canBeWorn = canBeWorn;
}
@Override
public void worn() {
canBeWorn.worn();
}
}
class Coat extends Mother{
public Coat(CanBeWorn canBeWorn) {
super(canBeWorn);
}
@Override
public void worn() {
super.worn();
System.out.println("穿上衣");
}
}
class Pants extends Mother{
public Pants(CanBeWorn canBeWorn) {
super(canBeWorn);
}
@Override
public void worn() {
super.worn();
System.out.println("穿裤子");
}
}
|
这个例子举的有些不太符合,但是基本上能说明装饰模式的过程。
1
2
3
| CanBeWorn canBeWorn = new UnderWear();
CanBeWorn coat = new Coat(canBeWorn);
CanBeWorn pants = new Pants(coat);
|

装饰模式的简化
大多数情况下,装饰模式的实现都要比上面给出的示意性例子要简单。
如果只有一个ConcreteComponent类,那么可以考虑去掉抽象的Component类(接口),把Decorator作为一个ConcreteComponent子类。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
| class UnderWear{
public void worn() {
System.out.print("穿内衣");
}
}
class Mother extends UnderWear{
private UnderWear underWear;
public Mother(UnderWear underWear){
this.underWear = underWear;
}
@Override
public void worn() {
underWear.worn();
}
}
class Coat extends Mother{
public Coat(UnderWear underWear) {
super(underWear);
}
@Override
public void worn() {
super.worn();
System.out.println("穿上衣");
}
}
class Pants extends Mother{
public Pants(UnderWear underWear) {
super(underWear);
}
@Override
public void worn() {
super.worn();
System.out.println("穿裤子");
}
}
|
类的代理
上面的代码用Kotlin实现
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
34
35
36
37
| interface CanBeWorn {
fun worn()
}
class UnderWear : CanBeWorn {
override fun worn() {
println("穿内衣")
}
}
abstract class Mother(val canBeWorn: CanBeWorn) : CanBeWorn {
override fun worn() {
canBeWorn.worn()
}
}
class Coat(canBeWorn: CanBeWorn) : Mother(canBeWorn) {
override fun worn() {
super.worn()
println("穿上衣")
}
}
class Pants(canBeWorn: CanBeWorn) : Mother(canBeWorn) {
override fun worn() {
super.worn()
println("穿裤子")
}
}
fun main(args: Array<String>){
Pants(Coat(UnderWear())).worn()
}
|
在Kotlin中可以使用by关键字将接口的实现委托到另一个对象。
所以上面的
1
2
3
4
5
6
| abstract class Mother(val canBeWorn: CanBeWorn) : CanBeWorn {
override fun worn() {
canBeWorn.worn()
}
}
|
可以修改如下
1
| abstract class Mother(val canBeWorn: CanBeWorn) : CanBeWorn by canBeWorn
|
覆盖代理成员
编译器会使用 override 覆盖的实现而不是委托对象中的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| interface Base {
fun printMessage()
fun printMessageLine()
}
class BaseImpl(val x: Int) : Base {
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
}
class Derived(b: Base) : Base by b {
override fun printMessage() { print("abc") }
}
fun main() {
val b = BaseImpl(10)
Derived(b).printMessage()
Derived(b).printMessageLine()
}
>>> abc10
|
注意,以这种方式重写的成员不会在委托对象的成员中调用 ,委托对象的成员只能访问其自身对接口成员实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| interface Base {
val message: String
fun print()
}
class BaseImpl(val x: Int) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(b: Base) : Base by b {
// 在 b 的 `print` 实现中不会访问到这个属性
override val message = "Message of Derived"
}
fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
println(derived.message)
}
>>> BaseImpl: x = 10
>>> Message of Derived
|
属性委托
不仅可以类代理,还可以代理类属性,监听属性变化。
1
2
3
| class Example {
var p: String by Delegate()
}
|
语法是: val/var <属性名>: <类型> by <表达式>。在 by 后面的表达式是该 委托, 因为属性对应的 get()(与 set())会被委托给它的 getValue() 与 setValue() 方法。 属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(与 setValue()——对于 var 属性)。 例如:
1
2
3
4
5
6
7
8
9
| class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
|
当我们从委托到一个 Delegate 实例的 p 读取时,将调用 Delegate 中的 getValue() 函数, 所以它第一个参数是读出 p 的对象、第二个参数保存了对 p 自身的描述 (例如你可以取它的名字)。 例如:
1
2
3
4
| val e = Example()
println(e.p)
>>> Example@33a17727, thank you for delegating ‘p’ to me!
|
标准委托
延迟属性lazy
lazy() 是接受一个 lambda 并返回一个 Lazy 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
| val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main() {
println(lazyValue)
println(lazyValue)
}
>>> computed!
>>> Hello
>>> Hello
|
可观察属性 Observable
Delegates.observable() 接受两个参数:初始值与修改时处理程序(handler)。 每当我们给属性赋值时会调用该处理程序(在赋值后执行)。它有三个参数:被赋值的属性、旧值与新值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main() {
val user = User()
user.name = "first"
user.name = "second"
}
>>> <no name> -> first
>>> first -> second
|