模板模式的主要應用場景爲:
一、在軟件的構造過程種,它經常有穩定的總體操做,但各個子步驟卻有着不少改變的需求,或者因爲固有的緣由二沒法與任務的總體框架同時實現;其定義一個操做中的算法骨架,而將一些步驟延遲(變化的部分)到子類中,模板的方法使得子類能夠不改變(複用)一個算法的結果便可重定義該算法的某些特定步驟。
二、更爲通俗的說法是,在父類中實現某個通用的流程,具體小的實現步驟在各個特定的子類中實現,這樣增強了代碼的複用,可是使用本設計模式的前提是存在一成不變的通用流程。ios
從圖中可與看出來存在兩個抽象類Document、Application,其中Document用於對文檔進行各種操做,固然起也是抽象類,由於對於不一樣的文檔須要細化操做細節,咱們僅看用於實現抽象操做一個文件的Application類,其具體的操做流程以下所示:算法
首先判斷這個文件是否能夠被打開,隨後使用DoCreateDocument()來產生處理文檔的特定類MyDocument,以便實現對不一樣文件的不一樣操做,最後經過一系列流程來完成打開過程。值得注意的是OpenDocument()中邏輯過程是穩定的不變的,其中每一步的具體實現是變化的,所以將OpenDocument設置爲非虛的成員函數,而將組成OpenDocument的子步驟,也就是CanOpenDocument()、AddDocument()、AboutToOpenDocument()與DoCreateDocument()設置爲虛的成員函數。設計模式
一、一次性實現一個算法的不變部分,並將可變的行爲留給子類來實現;
二、各子類中公共的行爲應被提取出來並集中到一個公共父類中以免代碼重複;
三、控制子類擴展。框架
一、使用C++訪問控制 在C++中,一個模板方法調用的可變化的那些操做能夠被定義爲保護成員。這保證他們只在模板方法中被調用(封裝原則,反正具體的實現步驟都須要封裝在一個特定的對外方法中,如前面的OpenDocument()方法中)。必須被重定義的可變化的成員函數必須被定義爲純虛函數,模板自身不需被重定義;所以將這個模板方法定義爲一個非虛成員函數。
二、儘可能減小須要重定義的部分 本方法原本就是將主要的工做交給庫的設計者(父類),而子類做爲直接的方法使用者無需掌握繁雜的使用流程,若須要重定義大量方法不就違反了這個規則。函數
#ifndef TEMPLATE_H #define TEMPLATE_H #include<iostream> #include<string> using std::string; class Abstract_class { public: Abstract_class(double re = 0, double img = 0) :re(re), img(img) {}; virtual ~Abstract_class(); void run() { step1(); step2(); step3(); step4(); } private: double re; double img; virtual void step1(string s=" ") = 0; virtual void step2(string s = " ") = 0; virtual void step3(string s = " ") = 0; virtual void step4(string s = " ") = 0; }; Abstract_class::~Abstract_class() { std::cout << "觸發Abstract_class析構函數" << std::endl; } class Concretclass1:public Abstract_class { private: double re; double img; void step1(string s) ; void step2(string s) ; void step3(string s) ; void step4(string s) ; public: Concretclass1(double re = 0, double img = 0) :re(re), img(img) {}; virtual ~Concretclass1() { std::cout << "觸發Concretclass1析構函數" << std::endl; }; }; void Concretclass1::step1(string s) { std::cout << "this is step1:+:" <<(re+img)<< std::endl; } void Concretclass1::step2(string s) { std::cout << "this is step2:-:" <<(re - img) << std::endl; } void Concretclass1::step3(string s) { std::cout << "this is step3:*:" << (re * img) << std::endl; } void Concretclass1::step4(string s) { std::cout << "this is step4:/:" << (re /img) << std::endl; } #endif // !TEMPLATE_H
在代碼中咱們定義了一個抽象類Abstract_class,這個類中包含一個該子類的通用處理流程run,可是run裏面的子實施流程是由各個子類實現的,所以根據以前的說法run方法應該設爲public且非虛的,他的子實施流程應該設爲private且是虛的(由於外界對象不須要看到這個方法,只須要看到run就好了,增長了封裝性)。
在子類Concretclass1中咱們實現了這些子實施流程,隨後直接使用run()方法就達到目的了。.c文件的內容爲:this
#include"template.h" int main() { Concretclass1* p1 = new Concretclass1(1.0, 2.0); p1->run(); delete p1; std::cin.get(); }
輸出結果爲:spa
能夠看到經過在Concretclass1調用從Abstract_class繼承的run()方法,成功的使用了子類的重定義的方法,雖然說優點不怎麼明顯哈哈。設計