故事始於小菜面試歸來,大鳥詢問感受,小菜感嘆「書到用時方恨少」。隨後話題轉向微軟認證考試的題庫風波,以及大鳥童年抄錯題的經歷。大鳥於是讓小菜寫一段「抄題」代碼,作為引子引出今天的主角——模板方法模式。
小菜寫了兩個類 TestPaperA 和 TestPaperB,分別代表兩位學生的試卷。每個類都完整實現了三道題的題目與答案:
class TestPaperA {
public:
void TestQuestion1() {
printf("楊過得到……玄鐵可能是【】a.球磨鑄鐵 b.馬口鐵 c.高速合金鋼 d.碳塑纖維 ");
printf("答案: b ");
}
void TestQuestion2() { /* 題目與答案 */ }
void TestQuestion3() { /* 題目與答案 */ }
};
// TestPaperB 結構相同,唯答案不同
小菜發現:題目完全一致,只有答案不同。這導致代碼極難維護——若老師改題目,兩個類都要改;若抄錯一題,後果嚴重。
大鳥提示:「老師出一份試卷,打印多份,學生只填答案。」於是將不變的題目放入父類,將變化的答案定義為抽象方法,強制子類實現。這就是模板方法模式的核心思想:
在抽象類中定義算法骨架,將某些步驟延遲到子類實現,不改變算法結構前提下重新定義步驟細節。

class TestPaper {
public:
void TestQuestion1() {
printf("楊過得到……玄鐵可能是【】a.球磨鑄鐵 b.馬口鐵 c.高速合金鋼 d.碳塑纖維 ");
printf("答案: %c ", Answer1());
}
void TestQuestion2() {
printf("楊過、程英……造成【】a.使這種植物不再害人 b.使一種珍稀物種滅絕 … ");
printf("答案: %c ", Answer2());
}
void TestQuestion3() {
printf("藍鳳凰致使……會給他們開什麼藥【】a.阿司匹林 b.牛黃解毒片 c.氟哌酸 … ");
printf("答案: %c ", Answer3());
}
protected:
virtual char Answer1() = 0;
virtual char Answer2() = 0;
virtual char Answer3() = 0;
};
class TestPaperA : public TestPaper {
protected:
char Answer1() override { return 'b'; }
char Answer2() override { return 'a'; }
char Answer3() override { return 'c'; }
};
class TestPaperB : public TestPaper {
protected:
char Answer1() override { return 'd'; }
char Answer2() override { return 'b'; }
char Answer3() override { return 'a'; }
};
現在 main() 僅需實例化具體試卷類,調用繼承自父類的 TestQuestion* 方法即可。題目邏輯集中維護,答案由子類決定,完美解耦。
TestQuestion1),調用受保護的抽象方法(Answer1)。從「抄試卷」到「模板方法」,我們看到設計模式如何將現實世界的最佳實踐轉化為軟體架構的靈活骨架。