在抽象類中實現算法不變部分(模板方法),將可變步驟聲明為抽象方法(基本方法)強制子類實現。不同子類提供不同實現,從而實現算法多樣性。這是基於繼承的代碼復用基石,也是面向對象設計核心。

一個抽象模板可對應多個具體模板,各自給出不同步驟實現。
// Template Method pattern -- Structural example
using System;
abstract class AbstractClass {
abstract public void PrimitiveOperation1();
abstract public void PrimitiveOperation2();
public void TemplateMethod() {
Console.WriteLine("In AbstractClass.TemplateMethod()");
PrimitiveOperation1();
PrimitiveOperation2();
}
}
class ConcreteClass : AbstractClass {
public override void PrimitiveOperation1() { Console.WriteLine("Called ConcreteClass.PrimitiveOperation1()"); }
public override void PrimitiveOperation2() { Console.WriteLine("Called ConcreteClass.PrimitiveOperation2()"); }
}
public class Client {
public static void Main() {
ConcreteClass c = new ConcreteClass(); c.TemplateMethod();
}
}
// Template Method pattern -- Real World example
using System; using System.Data; using System.Data.OleDb;
abstract class DataObject {
abstract public void Connect();
abstract public void Select();
abstract public void Process();
abstract public void Disconnect();
public void Run() { // 模板方法
Connect(); Select(); Process(); Disconnect();
}
}
class CustomerDataObject : DataObject {
private string connStr = "provider=Microsoft.JET.OLEDB.4.0; data source=c:\\nwind.mdb";
private string cmdStr; private DataSet ds;
public override void Connect() { /* 無操作 */ }
public override void Select() {
cmdStr = "select CompanyName from Customers";
OleDbDataAdapter da = new OleDbDataAdapter(cmdStr, connStr);
ds = new DataSet(); da.Fill(ds, "Customers");
}
public override void Process() {
DataTable dt = ds.Tables["Customers"];
foreach (DataRow dr in dt.Rows) Console.WriteLine(dr["CompanyName"]);
}
public override void Disconnect() { /* 無操作 */ }
}
public class TemplateMethodApp {
public static void Main() { new CustomerDataObject().Run(); }
}
註:需 C 盤根目錄有 nwind.mdb(Office 安裝目錄可尋)。
| 類型 | 定義者 | 實現者 | 說明 |
|---|---|---|---|
| 抽象方法 | 抽象類 | 具體子類 | 以 abstract 標記,強制子類實現 |
| 具體方法 | 抽象類 | 抽象類 | 已實現,子類不覆蓋 |
| 鉤子方法 | 抽象類 | 抽象類/子類 | 默認空實現,子類可選擇性擴展,命名常以 do 開頭 |
遵循此原則可將介面與實現、抽象與具體分離,最大化代碼復用,這正是模板方法模式的指引方向。