李建忠老師曾言:「若只掌握一種設計模式,那必定是模板方法模式。」此模式極簡卻無處不在,定義演算法骨架於父類,將易變步驟延遲至子類實現,實現碼復用與擴充點的最佳平衡。
意圖:定義演算法骨架,將特定步驟延遲至子類,不變更演算法結構即可重定義步驟。(GoF)
結構圖:

建築師使用模板方法:地基、結構、水電走線為固定流程 (骨架);房間格局、裝潢風格延遲至具體專案 (子類) 決定:

public abstract class DataAccessObject {
protected string _connStr; protected DataSet _ds;
public virtual void Connect() => _connStr = "Server=...;Database=Northwind";
public abstract void Select();
public abstract void Process();
public virtual void Disconnect() => _connStr = "";
// 模板方法:定義固定流程
public void Run() {
Connect(); Select(); Process(); Disconnect();
}
}
public class Categories : DataAccessObject {
public override void Select() {
var sql = "select CategoryName from Categories";
var da = new SqlDataAdapter(sql, _connStr);
_ds = new DataSet(); da.Fill(_ds, "Categories");
}
public override void Process() {
Console.WriteLine("Categories ----");
foreach (DataRow r in _ds.Tables["Categories"].Rows)
Console.WriteLine(r["CategoryName"]);
}
}
public class Products : DataAccessObject {
public override void Select() { /* select top 10 ProductName ... */ }
public override void Process() { /* 顯示 Products ... */ }
}
var dao = new Categories(); dao.Run();
dao = new Products(); dao.Run();
Connect/Disconnect 有預設實作 → virtual;Select/Process 無預設 → abstract。Run() 定義於基類,通常不允許子類覆寫 (可設 sealed 或 private/protected),屬於「好萊塢原則」:別調用我,讓我調用你。繼承 RichTextBox 並覆寫 OnSelectionChanged、OnTextChanged 等受保護虛擬方法,即為模板方法模式應用:框架定義控制項生命週期骨架,開發者於特定擴充點注入自訂邏輯。
public class MyRichTextBox : RichTextBox {
protected override void OnSelectionChanged(EventArgs e) {
// 自訂選取變更邏輯...
}
protected override void OnTextChanged(EventArgs e) {
// 自訂文字變更邏輯...
}
}
protected。(李建忠)模板方法模式雖簡單,卻是類庫設計與框架建構的核心技術,掌握它即掌握了面向物件復用的精髓。