一 、 一个实际应用模板方法的例子
下面的例子演示了数据库访问的模板方法。实际应用时,请确保 C 盘根目录下有 nwind.mdb 这个 Access 数
据库(可以从 Office 的安装目录下找到。中文版用户的请注意字段名可能有所不同)。
[C#] 纯文本查看 复制代码 using System;
using System.Data;
using System.Data.OleDb;
namespace ConsoleApplication1
{
// "AbstractClass"
abstract class DataObject
{
// Methods
public abstract void Connect();
public abstract void Select();
public abstract void Process();
public abstract void Disconnect();
// The "Template Method"
public void Run()
{
Connect();
Select();
Process();
Disconnect();
}
}
// "ConcreteClass"
class CustomerDataObject : DataObject
{
private string connectionString =
"provider=Microsoft.JET.OLEDB.4.0; "
+ "data source=c:\\nwind.mdb";
private string _commandString;
private DataSet _dataSet;
// Methods
public override void Connect()
{
// Nothing to do
}
public override void Select()
{
_commandString = "select CompanyName from Customers";
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
_commandString, connectionString);
_dataSet = new DataSet();
dataAdapter.Fill(_dataSet, "Customers");
}
public override void Process()
{
DataTable dataTable = _dataSet.Tables["Customers"];
foreach (DataRow dataRow in dataTable.Rows)
Console.WriteLine(dataRow["CompanyName"]);
}
public override void Disconnect()
{
// Nothing to do
}
}
/// <summary>
/// TemplateMethodApp test
/// </summary>
public class TemplateMethodApp
{
public static void Main(string[] args)
{
CustomerDataObject c = new CustomerDataObject();
c.Run();
}
}
}
二 、 模版方法模式中的方法
模版方法中的方法可以分为两大类:模版方法(Template Method)和基本方法(Primitive Method)。
模版方法
一个模版方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。这个模版
方法一般会在抽象类中定义,并由子类不加以修改地完全继承下来。
基本方法
基本方法又可以分为三种:抽象方法(Abstract Method)、具体方法(Concrete Method)和钩子方法(HookMethod)。
抽象方法:一个抽象方法由抽象类声明,由具体子类实现。在 C#语言里一个抽象方法以 abstract 关键字标示出来。
具体方法:一个具体方法由抽象类声明并实现,而子类并不实现或置换。在 C#语言里面,一个具体方法没有
abstract 关键字。
钩子方法:一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空实现,作为
方法的默认实现。(Visual FoxPro 中项目向导建立的项目会使用一个 AppHook 类实现监视项目成员变化,调
整系统结构的工作。)钩子方法的名字通常以 do 开始。
三 、 重构的原则
在对一个继承的等级结构做重构时,一个应当遵从的原则便是将行为尽量移动到结构的高端,而将状态尽量移动
到结构的低端。
1995 年,Auer 曾在文献【AUER95】中指出:
1. 应当根据行为而不是状态定义一个类。也就是说,一个类的实现首先建立在行为的基础之上,而不是建立在状态的基础之上。
2. 在实现行为时,是用抽象状态而不是用具体状态。如果一个行为涉及到对象的状态时,使用间接的引用而不是直接的引用。换言之,应当使用取值
方法而不是直接引用属性。
3. 给操作划分层次。一个类的行为应当放到一个小组核心方法(KernelMethods)里面,这些方法可以很方便地在子类中加以置换。
4. 将状态属性的确认推迟到子类中。不要在抽象类中过早地声明属性变量,应将它们尽量地推迟到子类中去声明。在抽象超类中,如果需要状态属性
的话,可以调用抽象的取值方法,而将抽象的取值方法的实现放到具体子类中。
如果能够遵从这样的原则,那么就可以在等级结构中将接口与实现分隔开来,将抽象与具体分割开来,从而保证
代码可以最大限度地被复用。这个过程实际上是将设计师引导到模版方法模式上去。 |