首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

設計模式之旅:模板方法模式詳解與雙重實作

     編輯:關於C#

摘要

模板方法模式是學習的第二個模式,理解容易卻極具實用價值。

意圖

定義演算法的骨架,將某些步驟延遲到子類別實作,讓子類別在不改變演算法整體架構下,重新定義特定步驟。

UML 表示

模板方法模式 UML

實務場景

原有一功能完整的類別,因需求變更,新類別與舊類別 60% 相同,僅 40% 不同。希望保留共同部分,僅改寫差異處。
例如:原生產「自動泡茶機」,現欲新增「自動泡咖啡機」,兩者架構與流程相似:

自動泡茶機自動泡咖啡機
step1: 煮開水step1: 煮開水
step2: 放入茶葉step2: 放入咖啡粉
step3: 倒入杯子step3: 倒入杯子
step4: 加檸檬step4: 加糖與奶精

step1 相同,step2~4 不同。設計 DrinkMachine 基類定義流程與 step1,step2~4 宣告為虛擬函數留給子類別實作,即為模板方法模式。

飲料機類別結構

此架構符合開放封閉原則 (OCP):新增飲料無需修改既有類別,僅需繼承並實作差異步驟。

簡述

模板方法模式就是將不同的成員函數用類別包裝,由衍生類別覆寫。

C++ 實作(繼承版)

/**/*
 (C) OOMusou 2007 https://oomusou.cnblogs.com

Filename : DP_TemplateMethodPattern1.cpp
Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use Template Method Pattern
Release : 03/31/2007 1.0
*/

#include <iostream>
using namespace std;

class DrinkMachine {
public:
 void makeDrink();

protected:
 void boilWater() { cout << "boil some water" << endl; }
 virtual void doPutIngredient() const = 0;
 virtual void doPourInCup() const = 0;
 virtual void doAddFlavoring() const = 0;
};

void DrinkMachine::makeDrink() {
 this->boilWater();
 this->doPutIngredient();
 this->doPourInCup();
 this->doAddFlavoring();
}

class TeaMachine : public DrinkMachine {
protected:
 void doPutIngredient() const { cout << "steep tea in boiling water" << endl; }
 void doPourInCup() const { cout << "pour tea in cup" << endl; }
 void doAddFlavoring() const { cout << "add lemon" << endl; }
};

class CoffeeMachine : public DrinkMachine {
protected:
 void doPutIngredient() const { cout << "brew coffee in boiling water" << endl; }
 void doPourInCup() const { cout << "pour coffee in cup" << endl; }
 void doAddFlavoring() const { cout << "add sugar and milk." << endl; }
};

int main() {
 cout << "Making Tea" << endl;
 DrinkMachine *theDrinkMachine = &TeaMachine();
 theDrinkMachine->makeDrink();

 cout << endl;
 cout << "Making Coffee" << endl;
 theDrinkMachine = &CoffeeMachine();
 theDrinkMachine->makeDrink();
}

執行結果:

Making Tea
boil some water
steep tea in boiling water
pour tea in cup
add lemon

Making Coffee
boil some water
brew coffee in boiling water
pour coffee in cup
add sugar and milk.

C++ 實作(Template 版,感謝 Quark 提供)

#include <iostream>
using namespace std;

template<typename T>
class DrinkMachine {
public:
 void makeDrink() {
 T* derived = (T*) this;

 this->boilWater();
 derived->doPutIngredient();
 derived->doPourInCup();
 derived->doAddFlavoring();
 }

protected:
 void boilWater() {
 cout << "boil some water" << endl;
 }
};

class TeaMachine : public DrinkMachine<TeaMachine> {
friend DrinkMachine<TeaMachine>;
protected:
 void doPutIngredient() const { cout << "steep tea in boiling water" << endl; }
 void doPourInCup() const { cout << "pour tea in cup" << endl; }
 void doAddFlavoring() const { cout << "add lemon" << endl; }
};

class CoffeeMachine : public DrinkMachine<CoffeeMachine> {
friend DrinkMachine<CoffeeMachine>;
protected:
 void doPutIngredient() const { cout << "brew coffee in boiling water" << endl; }
 void doPourInCup() const { cout << "pour coffee in cup" << endl; }
 void doAddFlavoring() const { cout << "add sugar and milk." << endl; }
};

int main() {
 cout << "Making Tea" << endl;
 DrinkMachine<TeaMachine> *pTeaMachine = &TeaMachine();
 pTeaMachine->makeDrink();

 cout << endl;
 cout << "Making Coffee" << endl;
 DrinkMachine<CoffeeMachine> *pCoffeeMachine = &CoffeeMachine();
 pCoffeeMachine->makeDrink();
}

備註:策略模式 vs 模板方法模式

兩者目的相同:為新需求的不同演算法提供擴充機制。但手法不同:

  • 策略模式:採用物件方式,利用委派改變演算法(執行期可動態切換)。
  • 模板方法模式:採用類別繼承方式改變演算法(編譯期決定,執行期無法改變)。

GoF 原文:
Template methods use inheritance to vary part of an algorithm. Strategies use delegation to vary the entire algorithm.

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved