軟體領域中的設計模式為開發人員提供了一種使用專家設計經驗的有效途徑。設計模式中運用了物件導向程式設計語言的重要特性:封裝、繼承、多態,真正領悟設計模式的精髓是可能一個漫長的過程,需要大量實踐經驗的積累。最近看設計模式的書,對於每個模式,用C++寫了個小例子,加深一下理解。主要參考《大話設計模式》和《設計模式:可複用物件導向軟體的基礎》(DP)兩本書。本文介紹原型模式和模板方法模式的實現。首先介紹原型模式,然後引出模板方法模式。
DP書上的定義為:用原型執行個體指定建立對象的種類,並且通過拷貝這些原型建立新的對象。其中有一個詞很重要,那就是拷貝。可以說,拷貝是原型模式的精髓所在。舉個現實中的例子來介紹原型模式。找工作的時候,我們需要準備簡曆。假設沒有列印裝置,因此需手寫簡曆,這些簡曆的內容都是一樣的。這樣有個缺陷,如果要修改簡曆中的某項,那麼所有已寫好的簡曆都要修改,工作量很大。隨著科技的進步,出現了列印裝置。我們只需手寫一份,然後利用列印裝置複印多份即可。如果要修改簡曆中的某項,那麼修改原始的版本就可以了,然後再複印。原始的那份手寫稿相當於是一個原型,有了它,就可以通過複印(拷貝)創造出更多的新簡曆。這就是原型模式的基本思想。下面給出原型模式的UML圖,以剛才那個例子為執行個體。
原型模式實現的關鍵就是實現Clone函數,對於C++來說,其實就是拷貝建構函式,需實現深拷貝,下面給出一種實現。
//父類class Resume{protected:char *name;public:Resume() {}virtual ~Resume() {}virtual Resume* Clone() { return NULL; }virtual void Set(char *n) {}virtual void Show() {}};
class ResumeA : public Resume{public:ResumeA(const char *str); //建構函式ResumeA(const ResumeA &r); //拷貝建構函式~ResumeA(); //解構函式ResumeA* Clone(); //複製,關鍵所在void Show(); //顯示內容};ResumeA::ResumeA(const char *str) {if(str == NULL) {name = new char[1]; name[0] = '\0'; }else {name = new char[strlen(str)+1];strcpy(name, str);}}ResumeA::~ResumeA() { delete [] name;}ResumeA::ResumeA(const ResumeA &r) {name = new char[strlen(r.name)+1];strcpy(name, r.name);}ResumeA* ResumeA::Clone() {return new ResumeA(*this);}void ResumeA::Show() {cout<<"ResumeA name : "<<name<<endl; }
這裡只給出了ResumeA的實現,ResumeB的實作類別似。使用的方式如下:
int main(){Resume *r1 = new ResumeA("A");Resume *r2 = new ResumeB("B");Resume *r3 = r1->Clone();Resume *r4 = r2->Clone();r1->Show(); r2->Show();//刪除r1,r2delete r1; delete r2;r1 = r2 = NULL;//深拷貝所以對r3,r4無影響r3->Show(); r4->Show();delete r3; delete r4;r3 = r4 = NULL;}
最近有個招聘會,可以帶上簡曆去應聘了。但是,其中有一家公司不接受簡曆,而是給應聘者發了一張簡曆表,上面有基本資料、教育背景、工作經曆等欄,讓應聘者按照要求填寫完整。每個人拿到這份表格後,就開始填寫。如果用程式實現這個過程,該如何做呢?一種方案就是用模板方法模式:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。我們的例子中,操作就是填寫簡曆這一過程,我們可以在父類中定義操作的演算法骨架,而具體的實現由子類完成。下面給出它的UML圖。
其中FillResume() 定義了操作的骨架,依次調用子類實現的函數。相當於每個人填寫簡曆的實際過程。接著給出相應的C++代碼。
//簡曆class Resume{protected: //保護成員virtual void SetPersonalInfo() {}virtual void SetEducation() {}virtual void SetWorkExp() {}public:void FillResume() {SetPersonalInfo();SetEducation();SetWorkExp();}};class ResumeA: public Resume{protected:void SetPersonalInfo() { cout<<"A's PersonalInfo"<<endl; }void SetEducation() { cout<<"A's Education"<<endl; }void SetWorkExp() { cout<<"A's Work Experience"<<endl; }};class ResumeB: public Resume{protected:void SetPersonalInfo() { cout<<"B's PersonalInfo"<<endl; }void SetEducation() { cout<<"B's Education"<<endl; }void SetWorkExp() { cout<<"B's Work Experience"<<endl; }};
使用方式如下:
int main(){Resume *r1;r1 = new ResumeA();r1->FillResume();delete r1;r1 = new ResumeB();r1->FillResume();delete r1;r1 = NULL;return 0;}
本人享有部落格文章的著作權,轉載請標明出處 http://blog.csdn.net/wuzhekai1985