设计模式笔记之 -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 /// 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 }
这种模式是经典的重用形式中的一种,其通用算法放置在基类中,并且通过继承在不同具体上下文中实现该通用算法。但是这里的代价就是派生类必须与其基类绑定在一起,如要使派生类不再绑定基类,则需要使用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 /// </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
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 /// </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 }
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 /// 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 }
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 /// 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 }
在这里需要排序的类对排序实现类一无所知,它只知道自己继承自接口,需要关系的只是实现接口方法即可,这样就大大提高了类的实用性,如果在自定义类中需要实现排序功能,那么它只需要继承相应的接口即可,这没有与高层算法的依赖。
结论:
Template Method和Strategy模式都可以用来分离高层算法和低层的具体实现细节,都允许高层算法独立于它的具体实现而重用,此外Strategy还提供了具体实现细节独立于高层算法的重用,不过为此付出的代价就是代码的复杂性提高了,增加了运行开销。