類的繼承你一定用過,派生類覆寫基類的方法你也一定用過,只是你可能不知道,這就是傳說中的一種設計模式……
1.模板方法模式簡介
模板方法模式是較簡單且常用的一種設計模式,是基於類的繼承的一種代碼複用技術,其結構只存在基類和派生類之間的繼承關係。模板方法是一個具體的方法,給出了一個頂層邏輯流程框架。
模板方法模式:
定義一個操作中的算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
2.模板方法結構
模板方法的結構很簡單,只有基類和派生類兩個角色:
- AbstractClass(基類):即抽象類,在基類中定義或聲明瞭一系列基本操作method,這些操作是具體或者抽象的,每一個操作都對應算法的一個步驟,在其派生類中可以重定義。基類中定義了一個模板方法(template method),它規定了算法的流程框架,模板方法由基類定義或聲明的一系列基本操作按照一定流程實現。
- ConcreteClass(派生類):實現在基類中聲明的抽象方法,也可以覆蓋在基類中已經實現的方法。
模板方法模式的UML圖如下:
模板方法模式的典型代碼如下:
#ifndef __DEMO_H__
#define __DEMO_H__
// 抽象類(基類)
class AbstractClass
{
public:
// 模板方法,定義一個算法的框架流程
void templateMethod(){
// do something
method1();
method2();
method3();
}
// 基本方法——公共方法
void mehtod1(){
// do something
}
// 基本方法2
virtual void method2() = 0;
// 基本方法3——默認實現
void mehtod3(){
// do something
}
};
// 具體類(派生類)
class ConcreteClass :public AbstractClass
{
public:
// 實現基本方法2
void method2(){
// do something
}
// 重定義基本方法3,覆蓋基類的方法3
void method3(){
// do something
}
};
#endif
3.模板方法模式代碼實例
某個指紋處理模塊可以在兩種模式下處理算法,即安全模式和非安全模式。在安全模式下,爲了保證數據安全,某個指紋識別流程需要對採得的指紋圖像進行加密,在處理圖像之前再對加密數據進行解密。而非安全模式這不需要加密解密過程。指紋算法流程如下:採圖——加密——解密——算法處理指紋——處理結果。現用模板方法模式模擬上述過程。
在這個實例中,Jungle首先定義了基類FingerprintModule,聲明瞭基本方法:採圖getImage()、判斷是否在安全模式isSafeMode()、加密encrypt()、解密decrypt()、處理指紋圖像processImage()、輸出結果output(),在基類中定義了一個模板方法algorithm(),該方法裏定義了指紋算法流程。
從基類FingerprintModule派生出3個子類,分別是FingerprintModuleA、FingerprintModuleB和FingerprintModuleC,三個子類的特點在於:
- FingerprintModuleA:安全模式,採用RSA祕鑰加解密,採用第一代版本算法處理指紋圖像;
- FingerprintModuleB:非安全模式,採用第二代版本算法處理指紋圖像;
- FingerprintModuleC:安全模式,採用DH祕鑰加解密,採用第一代版本算法處理指紋圖像;
該實例的UML圖如下:
代碼如下:
3.1.基類
// 基類
class FingerprintModule
{
public:
FingerprintModule(){}
void getImage(){
printf("採指紋圖像\n");
}
void output(){
printf("指紋圖像處理完成!\n");
}
virtual bool isSafeMode() = 0;
virtual void processImage() = 0;
// 加解密
virtual void encrypt() = 0;
virtual void decrypt() = 0;
// 模板方法
void algorithm(){
// 1.採圖
getImage();
// 2.安全模式下加密和解密
if (isSafeMode()){
// 2.1. 加密
encrypt();
// 2.2. 解密
decrypt();
}
// 3.處理Image
processImage();
// 4.處理結果
output();
}
};
3.2.派生類
// 派生類
class FingerprintModuleA :public FingerprintModule
{
public:
FingerprintModuleA(){}
void processImage(){
printf("使用 第一代版本算法 處理指紋圖像\n");
}
bool isSafeMode(){
printf("安全模式\n");
return true;
}
void encrypt(){
printf("使用RSA密鑰加密\n");
}
void decrypt(){
printf("使用RSA密鑰解密\n");
}
};
// 派生類
class FingerprintModuleB :public FingerprintModule
{
public:
FingerprintModuleB(){}
void processImage(){
printf("使用 第二代版本算法 處理指紋圖像\n");
}
bool isSafeMode(){
printf("非安全模式\n");
return false;
}
void encrypt(){}
void decrypt(){}
};
// 派生類
class FingerprintModuleC :public FingerprintModule
{
public:
FingerprintModuleC(){}
void processImage(){
printf("使用 第一代版本算法 處理指紋圖像\n");
}
bool isSafeMode(){
printf("安全模式\n");
return true;
}
void encrypt(){
printf("使用DH密鑰加密\n");
}
void decrypt(){
printf("使用DH密鑰解密\n");
}
};
3.3.客戶端代碼實例及效果
#include "FingerprintModule.h"
#include <Windows.h>
int main()
{
FingerprintModule *fp = new FingerprintModuleA();
fp->algorithm();
fp = new FingerprintModuleB();
fp->algorithm();
fp = new FingerprintModuleC();
fp->algorithm();
printf("\n\n");
system("pause");
return 0;
}
上述代碼運行結果如下:
4.總結
模板方法模式是基於類的繼承的一種設計模式,使用非常頻繁,被廣泛應用於框架設計。
優點:
- 在基類中定義算法的框架,並聲明一些流程方法,由具體派生類實現細節,派生類中的實現並不會影響基類定義的算法的框架流程;
- 公共行爲在基類中提供實現,有利於代碼複用;
- 派生類可以覆蓋基類的方法,重新實現某些方法,具有靈活性;
- 可以很方便的擴展和更換派生類而不影響基類和其他派生類,符合開閉原則和單一職責原則。
缺點:
- 模板方法模式要爲每一個不同的基本方法提供一個派生類,如果基類中基本方法很多,那系統中會定義很多個派生類,導致類的個數很多,系統更加龐大。
適用環境:
- 分割複雜算法,可以將算法的框架流程定義在基類中,設計爲模板方法;而具體的細節由派生類設計實現;
- 各個派生類的公共部分提取到基類中,以實現代碼複用;
- 派生類需要覆蓋基類的某些方法。
歡迎關注知乎專欄:Jungle是一個用Qt的工業Robot
歡迎關注Jungle的微信公衆號:Jungle筆記