设计模式笔记之 -Template Method & Strategy
Template Method:
通过抽象分离有共性的方法放入基类中,从而完成通用算法,将所有实现都交给该基类的抽象方法。
运用此模式主要在于建立抽象基类,制定抽象方法。
注意:不要滥用模式,如果把一个简单的问题复杂话了,那还不如不用模式,把一个简单的方法放在抽象基类里,并不能带来什么好处,反而增加了代码的复杂性。
冒泡排序的例子:
1
/// <summary>
2
/// Template Method 的冒泡排序的抽象基类
3
/// </summary>
4
public abstract class BubbleSorter
5
{
6
private int operations = 0;
7
protected int length = 0;
8
9
protected int DoSort()
10
{
11
operations = 0;
12
if(length <= 1) return operations;
13![]()
14
for(int nextToLast = length-2;nextToLast >=0;nextToLast--)
15
{
16
for(int index =0; index<=nextToLast; index++)
17
{
18
if(OutOfOrder(index))
19
Swap(index);
20
operations++;
21
}
22
}
23![]()
24
return operations;
25
}
26![]()
27
protected abstract void Swap(int index);
28
protected abstract bool OutOfOrder(int index);
29
}
30![]()
31![]()
32
/// <summary>
33
/// 整数型冒泡排序的实现类
34
/// </summary>
35
public class IntBubbleSorter : BubbleSorter
36
{
37
public IntBubbleSorter()
38
{
39
}
40![]()
41
private int[] array = null;
42
public int Sort(int[] theArray)
43
{
44
this.array = theArray;
45
base.length = array.Length;
46
return base.DoSort();
47
}
48![]()
49
protected override void Swap(int index)
50
{
51
int temp = this.array[index];
52
this.array[index] = array[index+1];
53
array[index + 1] = temp;
54
}
55![]()
56![]()
57
protected override bool OutOfOrder(int index)
58
{
59
return (array[index]<array[index+1]);
60
}
61![]()
62![]()
63![]()
64
}

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

这种模式是经典的重用形式中的一种,其通用算法放置在基类中,并且通过继承在不同具体上下文中实现该通用算法。但是这里的代价就是派生类必须与其基类绑定在一起,如要使派生类不再绑定基类,则需要使用Strategy模式。
Strategy:
可以看到上面的排序类违反了依赖倒置原则(DIP),那么把Template Method模式变型,通过接口的桥接作用实现解耦合,如下使用Strategy模式的冒泡排序:
1
/// <summary>
2
/// 冒泡排序
3
/// </summary>
4
public class BubbleSorter
5
{
6
private int operations = 0;
7
private int length = 0;
8
private ISortHandle itsSortHandle = null;
9![]()
10
public BubbleSorter(ISortHandle handle)
11
{
12
itsSortHandle = handle;
13
}
14![]()
15
/// <summary>
16
/// 开始排序
17
/// </summary>
18
/// <param name="upOrDown">是正序还是倒序</param>
19
/// <returns>返回处理的次数</returns>
20
public int Sort(bool upOrDown)
21
{
22
length = itsSortHandle.Length();
23
operations = 0;
24
if(length <= 1)
25
return operations;
26![]()
27
for(int nextToLast = length-2; nextToLast>=0;nextToLast--)
28
{
29
for(int index=0;index <= nextToLast;index++)
30
{
31
if(itsSortHandle.OutOfOrder(index) == upOrDown)
32
itsSortHandle.Swap(index);
33
operations++;
34
}
35
}
36![]()
37
return operations;
38
}
39![]()
40
/// <summary>
41
/// 开始排序
42
/// </summary>
43
/// <param name="array">传入需要排序的对象</param>
44
/// <param name="upOrDown">是正序还是倒序</param>
45
/// <returns>返回处理的次数</returns>
46
public int Sort(object array , bool upOrDown)
47
{
48
itsSortHandle.SetArray(array);
49
return Sort(upOrDown);
50
}
51![]()
52![]()
53
}//class

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

1
/// <summary>
2
/// 提供排序的接口函数
3
/// </summary>
4
public interface ISortHandle
5
{
6
void Swap(int index);
7
bool OutOfOrder(int index);
8
int Length();
9
void SetArray(object array);
10
}

2

3

4

5

6

7

8

9

10

1
/// <summary>
2
/// IntSortHandle 的摘要说明。
3
/// </summary>
4
public class IntSortHandle : ISortHandle
5
{
6
private int[] array = null;
7
public IntSortHandle(int[] inValue)
8
{
9
this.array = inValue;
10
}
11![]()
12
public IntSortHandle()
13
{
14
}
15![]()
16
public void Swap(int index)
17
{
18
int temp = array[index];
19
array[index] = array[index + 1];
20
array[index+1] = temp;
21
}
22![]()
23
public void SetArray(object array)
24
{
25
this.array = (int[])array;
26
}
27![]()
28
public bool OutOfOrder(int index)
29
{
30
return (array[index] > array[index + 1]);
31
}
32![]()
33
public int Length()
34
{
35
if(null == this.array)
36
throw new Exception("数组还没赋值");
37
return array.Length;
38
}
39![]()
40
public int[] GetArray()
41
{
42
return this.array;
43
}
44![]()
45
}

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

1
/// <summary>
2
/// BubbleSorter_Test 的摘要说明。
3
/// </summary>
4
[TestFixture]
5
public class BubbleSorter_Test
6
{
7
public BubbleSorter_Test()
8
{
9
}
10![]()
11
[Test]
12
public void Test_IntSort()
13
{
14
int[] invalue = new int[]{3,5,2,7,8,1,9};
15
int[] result1 = new int[]{1,2,3,5,7,8,9};
16
int[] result2 = new int[]{9,8,7,5,3,2,1};
17![]()
18
IntSortHandle ish = new IntSortHandle(invalue);
19
BubbleSorter bs = new BubbleSorter(ish);
20![]()
21
Console.WriteLine("交换的次数:" + bs.Sort(true));
22
Assert.AreEqual(result1,ish.GetArray());
23![]()
24
Console.WriteLine("交换的次数2:" + bs.Sort(invalue,false));
25
Assert.AreEqual(result2,ish.GetArray());
26
}
27
}

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

在这里需要排序的类对排序实现类一无所知,它只知道自己继承自接口,需要关系的只是实现接口方法即可,这样就大大提高了类的实用性,如果在自定义类中需要实现排序功能,那么它只需要继承相应的接口即可,这没有与高层算法的依赖。
结论:
Template Method和Strategy模式都可以用来分离高层算法和低层的具体实现细节,都允许高层算法独立于它的具体实现而重用,此外Strategy还提供了具体实现细节独立于高层算法的重用,不过为此付出的代价就是代码的复杂性提高了,增加了运行开销。