1. 程式人生 > >設計模式C++實現(5)——原型模式、模板方法模式

設計模式C++實現(5)——原型模式、模板方法模式

       軟體領域中的設計模式為開發人員提供了一種使用專家設計經驗的有效途徑。設計模式中運用了面向物件程式語言的重要特性:封裝、繼承、多型,真正領悟設計模式的精髓是可能一個漫長的過程,需要大量實踐經驗的積累。最近看設計模式的書,對於每個模式,用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,r2
	delete 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