template method模式和strategy模式
template method模式和strategy模式都是关注对象的行为的,按照依赖倒置的方法来分离抽象和具体的实现,但是两者的实现方法不同。template method模式应用了面向对象中继承的思想,而strategy模式则应用了委托的思想,从template method模式和strategy模式中也可以看到面向对象世界中abstract类和interface的异同。实际上这两种模式我们经常会用到,只是可能没有意识到而已。
Template method的常见用法是将运算的骨架放在基类中,然后将某些具体的算法放到子类里面实现,这样就可以使得子类不改变算法的结构即可重定义该算法的某些特定步骤。
Template method的一个例子:Report服务。
假定系统中有一系列Report,Booking Report, Billing Report, Aging Report…。这些Report参数不一样,界面不一样,逻辑不一样,但是也有一些有共同点,验证权限,结果输出,Report载入步骤等等。那么为了避免重复代码,有一个较好的可扩充的结构,我们把这些共同点extract到一个基类中ReportBase,简单示例如下:
public class ReportBase
{
public void OpenReport(string reportId)
{
if(UserIsInRole()==true)
{
Initialize();
LoadSavedReport();
}
}
private void Initialize()
{
InitializeControl();
SetDefaultValue();
}
protected abstract void InitializeControl()
{
}
protected abstract void LoadSavedReport ()
{
}
{
}
}
ReportBase.OpenReport()是一个Template,定义了算法的每一步,并且允许子类提供其中某些步的具体实现。
我们可以看到Template Method的主要特点是,将各个子类中不变的行为提取到基类中实现,可变的部分留给子类自己实现,而且基类中定义了一个相对稳定的结构,也就是一个模版Template,模版中的某些步骤留待子类来实现,基类还可以控制子类的扩展,允许某些子类在某些点上作扩展。对于基类来说意义在于控制整个结构,减少重复代码,对于子类来说意义在于不改变算法的机构可以方便的提供一种实现。
从Template Method中可以看到Framework和控制反转的精神,不是每个具体做事情的子类调用所需的Library完成某个行为,而是提供具体实现,让高层的代码来调用。
(Hollywood Principle: 当高层的模块依赖低层的模块时,由高层的模块决定何时以及如何调用底层模块,也就是说高层模块对底层模块讲:Don’t call me, we’ll call you)
当然Template Method模式和strategy模式在现在看来都已经是很自然的都东西。
应用Template Method需要先对代码逻辑作分析,哪些放到基类,哪些留给子类,当然这属于OO世界最基本的东西。如果现有的代码重构到Template Method可以参考《Refactoring》Dealing with Generalization一章。
应用Template Method需要注意的是基类需要指明那些行为是子类必须重定义的,哪些行为是允许子类重定义的(Abstract method和Hook Method),具体到C#的语法就是abstract和virtual定义。而且需要仔细评估那些子类必须重定义的行为,避免子类中需要做过多的重定义工作。对于可以允许子类重定义的行为来说好比提供了一个hook,在基类中通常是一个空操作,允许子类在这一点上扩展基类的行为。
另外一点需要注意的是继承属于很强的耦合关系,过多的继承关系会使系统变得僵化难以变化,往往会用对象的组合来代替继承。
一个替代继承的模式是strategy模式。
参考
《Head.First.Design.Patterns].Head.First.Design.Patterns》
《敏捷软件开发 原则、模式与实践》
打印 | 张贴于 2005-09-09 13:06:00 | Tag:拥抱变化

留言反馈
DirectoryEntry类的构造函数通过指定Path就可以绑定到DC。例如,我们常用的LDAP:
Abstract method declarations are only permitted in abstract classes.
Because an abstract method declaration provides no actual implementation, there is no method body; the method declaration simply ends with a semicolon and there are no braces ({ }) following the signature. For example:
public abstract void MyMethod();