[读书笔记]策略模式

_《HeadFirst设计模式》读书笔记系列_

看起来美好的面向对象

学过面向对象的都知道继承可以重用父类中的一些方法,从而减少很多劳动量:

现有场景如下:

玩具工厂生产各种鸭子,有优雅鸭子(ElegantDuck),爵士鸭子(DukeDuck),霸王鸭子(KingDuck),均继承自超类鸭子(Duck),他们都是可以飞行的,并且在飞行时执行统一的方法 Fly() —— 喊叫”I’m flying.” 于是优雅、爵士和霸王顺理成章地继承了超类的飞行方法。

1
2
3
4
5
6
7
8
void Fly()
{
Console.WriteLine("I'm flying.");
}

于是整体的代码大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Duck//超类
{
public void Fly()
{
    Console.WriteLine("I'm flying");
}
}//class Duck
class ElegantDuck: Duck{}
class DukeDuck: Duck{}
class KingDuck: Duck{}

应用了面向对象之后一切看起来都是那么的优美,没有重复的代码,整洁如新。

不久之后,为了适应低龄儿童,玩具工厂决定加入新的花样——橡皮鸭子(RubberDuck),但是这种橡皮鸭子是不能飞行的,当被调用方法Fly()时会输出”I can’t fly!”

于是顺理成章地我们可以重写(override)超类中的Fly()方法,于是有橡皮鸭子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class RubberDuck: Duck
{
public void override Fly()//重写超类中的Fly()
{
Console.WriteLine("WOW!I can't fly!");
}
}

到这里为止,一切都是循规蹈矩顺理成章,也没有什么值得争论的东西。

可是最后,出现了一件可怕的事情。

噩梦的开始

自玩具工厂推出面向低龄儿童的玩具之后收到社会各界的广泛好评,销售量大增,于是高层决定打铁成热推出几款新的产品——木头鸭子(WoodDuck), 塑料鸭子(PlasticDuck),这两款鸭子都不能飞行,将和橡皮鸭子执行同样的飞行方法。

问题出现了:难道这时我必须重写这3个不会飞的鸭子类中的Fly()方法???这三只鸭子的飞行方法也都是一样的,却仍然要写三次?天哪,这样太不优美了吧!!!光是想起来就让人觉得丑陋啊!

解决方案:

不再将飞行行为Fly()看作是Duck的方法,而是将整个飞行作为Duck的属性。光看文字太抽象了,别急,慢慢来,这句话用代码表示大概就是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Duck
{
FlyBehavior flyBehavior;//属性FlyBehavoir是飞行行为的接口,子类可以在各自的构造函数或者其他地方指定对应的飞行行为
public void Fly()
{
flyBehavior.Fly();//属性的具体表现方式
}
}

这样就将FlyBehavior和Duck组合在了一起。

于是全新的鸭子系列闪亮出炉了!

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//飞行行为:
interface IFlyBehavoir
{
void Fly();
}
class Flyable : IFlyBehavoir//能飞的
{
void IFlyBehavoir.Fly()
{
Console.WriteLine("I'm flying");
}
}
class UnFlyable:IFlyBehavoir//不能飞的
{
void IFlyBehavoir.Fly()
{
Console.WriteLine("WOW!I can't fly!");
}
}
//鸭子系类
class Duck//超类
{
protected IFlyBehavoir flyBehavoir;
public void Fly()
{
flyBehavoir.Fly();
}
}//class Duck
class ElegantDuck : Duck
{
public ElegantDuck()
{
//绑定具体的飞行行为
this.flyBehavoir = new Flyable();//其实这里我一直搞不懂到底是该用base还是this...
}
}
class DukeDuck : Duck
{
public DukeDuck()
{
this.flyBehavoir = new Flyable();
}
}
class KingDuck : Duck
{
public KingDuck()
{
this.flyBehavoir = new Flyable();
}
}
class RubberDuck : Duck
{
public RubberDuck()
{
this.flyBehavoir = new UnFlyable();
}
}
class WoodDuck : Duck
{
public WoodDuck()
{
this.flyBehavoir = new UnFlyable();
}
}
class PlasticDuck : Duck
{
public PlasticDuck()
{
this.flyBehavoir = new UnFlyable();
}
}

虽然多了不少的代码,但是减少了重复的代码,使得代码更容易被修改。

整体类图如下:

鸭子的行为不是继承来的,而是和适当的行为对象“组合”而来的。

总结:

策略模式的书本定义:定义了算法族,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

我对这句话的理解是:此模式可以针对不同客户对功能的需求不同,从策略集中取出相应的执行方法,因此得名“策略模式”。

看图说话如下: