设计模式笔记之 -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
}
/// <summary>2
/// Template Method 的冒泡排序的抽象基类3
/// </summary>4
public abstract class BubbleSorter5
{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 : BubbleSorter36
{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
}
这种模式是经典的重用形式中的一种,其通用算法放置在基类中,并且通过继承在不同具体上下文中实现该通用算法。但是这里的代价就是派生类必须与其基类绑定在一起,如要使派生类不再绑定基类,则需要使用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
/// <summary>2
/// 冒泡排序3
/// </summary>4
public class BubbleSorter5
{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
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
}
/// <summary>2
/// 提供排序的接口函数3
/// </summary>4
public interface ISortHandle5
{6
void Swap(int index);7
bool OutOfOrder(int index);8
int Length();9
void SetArray(object array);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
}
/// <summary>2
/// IntSortHandle 的摘要说明。3
/// </summary>4
public class IntSortHandle : ISortHandle5
{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
}
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
}
/// <summary>2
/// BubbleSorter_Test 的摘要说明。3
/// </summary>4
[TestFixture]5
public class BubbleSorter_Test6
{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
}
在这里需要排序的类对排序实现类一无所知,它只知道自己继承自接口,需要关系的只是实现接口方法即可,这样就大大提高了类的实用性,如果在自定义类中需要实现排序功能,那么它只需要继承相应的接口即可,这没有与高层算法的依赖。
结论:
Template Method和Strategy模式都可以用来分离高层算法和低层的具体实现细节,都允许高层算法独立于它的具体实现而重用,此外Strategy还提供了具体实现细节独立于高层算法的重用,不过为此付出的代价就是代码的复杂性提高了,增加了运行开销。


浙公网安备 33010602011771号