1、模式定義
模板方法模式又叫模板模式,該模式在一個方法中定義一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟。
模板方法模式將主要的方法定義為 final ,防止子類修改演算法骨架,將子類必須實現的方法定義為 abstract 。而普通的方法(無 final 或 abstract 修飾)則稱之為鉤子( hook )。
2、UML類圖
3、範例程式碼
Journey.php
buyAFlight(); $this->takePlane(); $this->enjoyVacation(); $this->buyGift(); $this->takePlane(); } /** * 該方法必須被子類實現, 這是模板方法模式的核心特性 */ abstract protected function enjoyVacation(); /** * 這個方法也是演算法的一部分,但是是可選的,只有在需要的時候才去重寫它 */ protected function buyGift() { } /** * 子類不能訪問該方法 */ private function buyAFlight() { echo "Buying a flight\n"; } /** * 這也是個final方法 */ final protected function takePlane() { echo "Taking the plane\n"; }}
BeachJourney.php
CityJourney.php
4、測試代碼
Tests/JourneyTest.php
expectOutputRegex('#sun-bathing#'); $journey->takeATrip(); } public function testCity() { $journey = new TemplateMethod\CityJourney(); $this->expectOutputRegex('#drink#'); $journey->takeATrip(); } /** * 在PHPUnit中如何測試抽象模板方法 */ public function testLasVegas() { $journey = $this->getMockForAbstractClass('DesignPatterns\Behavioral\TemplateMethod\Journey'); $journey->expects($this->once()) ->method('enjoyVacation') ->will($this->returnCallback(array($this, 'mockUpVacation'))); $this->expectOutputRegex('#Las Vegas#'); $journey->takeATrip(); } public function mockUpVacation() { echo "Fear and loathing in Las Vegas\n"; }} 5、總結
模板方法模式是基於繼承的代碼複用技術,模板方法模式的結構和用法也是物件導向設計的核心之一。在模板方法模式中,可以將相同的代碼放在父類中,而將不同的方法實現放在不同的子類中。
在模板方法模式中,我們需要準備一個抽象類別,將部分邏輯以具體方法以及具體建構函式的形式實現,然後聲明一些抽象方法來讓子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩餘的邏輯有不同的實現,這就是模板方法模式的用意。模板方法模式體現了物件導向的諸多重要思想,是一種使用頻率較高的模式。