一、模式简介
1、模板方法
用意:准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方 式实现这些抽象方法,从而对剩余的逻辑有不同的实现。
2、策略
用意:针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换 。
二、实例比较
Template Method模式和Strategy模式都可以分离通用的算法和具体的上下文。
Template Method模式通过继承解决,Strategy通过委托解决。
分别用以上两个模式来实现冒泡排序。
1、 Template Method
{
private int operations = 0 ;
protected int length = 0 ;
protected int DoSort()
{
operations = 0 ;
if (length < 1 )
return operations;
for ( int nextToLast = length - 1 ; nextToLast >= 0 ; nextToLast -- )
{
for ( int index = 0 ; index < nextToLast; index ++ )
{
if (OutOfOrder(index))
Swap(index);
operations ++ ;
}
}
return operations;
}
protected abstract void Swap( int index);
protected abstract Boolean OutOfOrder( int index);
}
public class DoubleBubblerSorter:BubbleSorter
{
private double [] array = null ;
public int Sort( double [] a)
{
array = a;
length = a.Length;
return DoSort();
}
protected override void Swap( int index)
{
double t = array[index];
array[index] = array[index + 1 ];
array[index + 1 ] = t;
}
protected override Boolean OutOfOrder( int index)
{
return (array[index] > array[index + 1 ]);
}
public void PrintArray()
{
foreach (var a in array)
{
Console.WriteLine(a);
}
}
}
通用算法Swap(交换数据),OutOfOrder(是否该交换) 被放置在基类中,通过继承,DoubleBubblerSorter 实现了针对Double Array的BubblerSorter 。
继承关系是强耦合的,BubbleSorter中包含了冒泡排序的算法 DoSort。 DoubleBubblerSorter 依 赖于BubbleSorter。
运行一下
bs.Sort( new double [] { 1 , 2.2 , 3 , 4 , 2.1 , 3.5 , 3.8 , 4.5 , 1.6 });
bs.PrintArray();
2、Strategy
{
private int operations = 0 ;
private int length = 0 ;
private SortHandle sorthandle = null ;
public BubbleSorter(SortHandle sh)
{
sorthandle = sh;
}
public int Sort( object array)
{
sorthandle.SetArray(array);
length = sorthandle.Length();
operations = 0 ;
if (length < 1 )
return operations;
for ( int nextToLast = length - 1 ; nextToLast >= 0 ; nextToLast -- )
{
for ( int index = 0 ; index < nextToLast; index ++ )
{
if (sorthandle.OutOfOrder(index))
sorthandle.Swap(index);
operations ++ ;
}
}
return operations;
}
}
public interface SortHandle
{
void Swap( int index);
Boolean OutOfOrder( int index);
int Length();
void SetArray( object array);
}
public class IntSortHandle : SortHandle
{
private int [] array = null ;
public void Swap( int index)
{
int t = array[index];
array[index] = array[index + 1 ];
array[index + 1 ] = t;
}
public Boolean OutOfOrder( int index)
{
return (array[index] > array[index + 1 ]);
}
public void SetArray( object array)
{
this .array = ( int [])array;
}
public int Length()
{
return array.Length;
}
public void PrintArray()
{
foreach (var a in array)
{
Console.WriteLine(a);
}
}
}
上面,扮演Strategy中Context角色的BubbleSorter,包含了冒泡的具体算法。
IntSortHandle 对BubbleSorter却是一无所知的,它不需要依赖于实现了冒泡排序算法的 BubbleSorter。
在TemplateMethod中,Swap和OutOfOrder的实现依赖于冒泡排序算法(DoubleBubblerSorter 依赖于BubbleSorter )。
而在 Strategy中,IntSortHandle 不需要依赖于 BubbleSorter,所以我们可以在其他的排序中使用IntSortHandle 。
同样,运行如下:
BubbleSorter2 bs2 = new BubbleSorter2(ibs);
bs2.Sort( new int [] { 8 , 2 , 3 , 1 , 5 });
ibs.PrintArray();
通过上面的例子我们可以看到Strategy模式的好处, 因为Strategy模式完全的遵守DIP原则,所以每个具体实现都可以被多个不同的通 用算法操作。
三、补充说明
依赖倒置原则(DIP)
DIP解释:
1、高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
2、抽象不应该依赖于细节。细节应该依赖于抽象。
DIP中依赖于抽象的把握:
1、任何变量都不应该持有一个指向具体来的引用。
2、任何类都不应该从具体来派生。
3、任何方法都不应该覆写它的任何基类中的已经实现的方法。
我们在项目中的做法:
每个较高层次都为它所需要的服务声明一个抽象接口,较低的层次实现了这些抽象接口。
每个高层类都通过该抽象接口使用下一层,这样高层就不依赖于低层。低层反而依赖于高层中声明的抽象服务接口。
可以参考我之前写的一篇文章:谈谈我对DI 的 理解 。
四、参考资料