定義
定義一個操作中演算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
設計的原則和思想
- 解耦的是 模板方法(演算法)和方法(演算法)步驟。
- 不變部分是方法步驟,變化部分是模板方法。
- 核心思想是同一個步驟,不同的事情。
一句話概括設計模式
父類控制流程,子類負責具體實現。
結構中包含的角色
- AbstractClass(抽象類)
- ConcreteClass(具體子類)
最小可表達程式碼
abstract class AbstractTemplate
{
public function templateMethod()
{
$this->primitiveOperation1();
$this->primitiveOperation2();
if ($this->primitiveOperation3()) {
echo '執行鉤子';
}
}
public function primitiveOperation1()
{
echo '我是具體方法';
}
public abstract function primitiveOperation2();
public function primitiveOperation3() : bool
{
return false;
}
}
class ConcreteTemplate extends AbstractTemplate
{
public function primitiveOperation2()
{
echo '我是實現的抽象方法';
}
public function primitiveOperation3() : bool
{
return true;
}
}
$template = new ConcreteTemplate();
$template->templateMethod();
優點
- 可實現反向控制結構,透過子類覆蓋父類的鉤子方法來決定某一特定步驟是否需要執行。
- 封裝不變部分,擴充套件可變部分。
- 提取公共程式碼,便於維護。
- 行為由父類控制,子類實現。
缺點
- 每一個基本方法的不同實現都需要一個子類來實現,如果父類中可變的基本方法太多,將會導致類的個數增加。
- 部分客戶端可能會受到演算法框架的限制。
何時使用
- 流程不變,流程內的實現可以被替換的時候。
- 多個演算法幾乎一樣時。
- 只希望擴充套件某個特定演算法步驟,而不是整個演算法或其結構時。
- 有多個子類共有的方法,且邏輯相同。
實際應用場景
- 建房子,地基、走線、水管都一樣,但是裝修是不一樣的。
- 報表。報表頭,報表內容,報表結尾,這些步驟都是一樣的。
- 考試。不同的科目,考試流程是一樣的,但是考試內容是不一樣的。
- 面試。面試流程都是一樣的,不一樣的是面試內容。
- 同步回撥。
模板模式的作用
複用
子類可以複用父類别範本方法的程式碼。
擴充套件
使用者可以在不修改框架原始碼的情況下,擴充套件定製化框架的功能。
模板方法模式 VS 回撥(Callback)
- 同步回撥跟模板模式幾乎一致。它們都是在一個大的演算法骨架中,自由替換其中的某個步驟,起到程式碼複用和擴充套件的目的。
- 回撥基於組合關係來實現,把一個物件傳遞給另一個物件,是一種物件之間的關係。模板模式基於繼承關係來實現,是一種類之間的關係。
- 回撥可以使用匿名類來建立回撥物件,可以不用事先定義類。而模板模式針對不同的實現都要定義不同的子類。
- 模板方法中,子類必須實現所有的抽象方法。而回撥只需要往用到的模板方法中注入回撥物件即可。
回撥程式碼
class Template
{
public function templateMethod(BaseCallback $callback)
{
$callback->callbackMethod();
}
}
interface BaseCallback
{
public function callbackMethod();
}
class SubCallback implements BaseCallback
{
public function callbackMethod()
{
echo "SubCallback callbackMethod";
}
}
$template = new Template();
$subCallback = new SubCallback();
$template->templateMethod($subCallback);
本作品採用《CC 協議》,轉載必須註明作者和本文連結