1. 程式人生 > >設計模式C++實現(2)——策略模式

設計模式C++實現(2)——策略模式

       軟體領域中的設計模式為開發人員提供了一種使用專家設計經驗的有效途徑。設計模式中運用了面向物件程式語言的重要特性:封裝、繼承、多型,真正領悟設計模式的精髓是可能一個漫長的過程,需要大量實踐經驗的積累。最近看設計模式的書,對於每個模式,用C++寫了個小例子,加深一下理解。主要參考《大話設計模式》和《設計模式:可複用面向物件軟體的基礎》兩本書。本文介紹策略模式的實現。

       策略模式是指定義一系列的演算法,把它們一個個封裝起來,並且使它們可相互替換。本模式使得演算法可獨立於使用它的客戶而變化。也就是說這些演算法所完成的功能一樣,對外的介面一樣,只是各自實現上存在差異。用策略模式來封裝演算法,效果比較好。下面以快取記憶體(Cache)的替換演算法為例,實現策略模式。

       什麼是Cache的替換演算法呢?簡單解釋一下, 當發生Cache缺失時,Cache控制器必須選擇Cache中的一行,並用欲獲得的資料來替換它。所採用的選擇策略就是Cache的替換演算法。下面給出相應的UML圖。


       ReplaceAlgorithm是一個抽象類,定義了演算法的介面,有三個類繼承自這個抽象類,也就是具體的演算法實現。Cache類中需要使用替換演算法,因此維護了一個  ReplaceAlgorithm的物件。這個UML圖的結構就是策略模式的典型結構。下面根據UML圖,給出相應的實現。

       首先給出替換演算法的定義。

//抽象介面
class ReplaceAlgorithm
{
public:
	virtual void Replace() = 0;
};
//三種具體的替換演算法
class LRU_ReplaceAlgorithm : public ReplaceAlgorithm
{
public:
	void Replace() { cout<<"Least Recently Used replace algorithm"<<endl; }
};

class FIFO_ReplaceAlgorithm : public ReplaceAlgorithm
{
public:
	void Replace() { cout<<"First in First out replace algorithm"<<endl; }
};
class Random_ReplaceAlgorithm: public ReplaceAlgorithm
{
public:
	void Replace() { cout<<"Random replace algorithm"<<endl; }
};

         接著給出Cache的定義,這裡很關鍵,Cache的實現方式直接影響了客戶的使用方式,其關鍵在於如何指定替換演算法。

         方式一:直接通過引數指定,傳入一個特定演算法的指標。

//Cache需要用到替換演算法
class Cache
{
private:
	ReplaceAlgorithm *m_ra;
public:
	Cache(ReplaceAlgorithm *ra) { m_ra = ra; }
	~Cache() { delete m_ra; }
	void Replace() { m_ra->Replace(); }
};
          如果用這種方式,客戶就需要知道這些演算法的具體定義。只能以下面這種方式使用,可以看到暴露了太多的細節。
int main()
{
	Cache cache(new LRU_ReplaceAlgorithm()); //暴露了演算法的定義
	cache.Replace();
	return 0;
}
          方式二:也是直接通過引數指定,只不過不是傳入指標,而是一個標籤。這樣客戶只要知道演算法的相應標籤即可,而不需要知道演算法的具體定義。
//Cache需要用到替換演算法
enum RA {LRU, FIFO, RANDOM}; //標籤
class Cache
{
private:
	ReplaceAlgorithm *m_ra;
public:
	Cache(enum RA ra) 
	{ 
		if(ra == LRU)
			m_ra = new LRU_ReplaceAlgorithm();
		else if(ra == FIFO)
			m_ra = new FIFO_ReplaceAlgorithm();
		else if(ra == RANDOM)
			m_ra = new Random_ReplaceAlgorithm();
		else 
			m_ra = NULL;
	}
	~Cache() { delete m_ra; }
	void Replace() { m_ra->Replace(); }
};
          相比方式一,這種方式用起來方便多了。其實這種方式將簡單工廠模式與策略模式結合在一起,演算法的定義使用了策略模式,而Cache的定義其實使用了簡單工廠模式。
int main()
{
	Cache cache(LRU); //指定標籤即可
	cache.Replace();
	return 0;
}
          上面兩種方式,建構函式都需要形參。建構函式是否可以不用引數呢?下面給出第三種實現方式。

          方式三:利用模板實現。演算法通過模板的實參指定。當然了,還是使用了引數,只不過不是建構函式的引數。在策略模式中,引數的傳遞難以避免,客戶必須指定某種演算法。

//Cache需要用到替換演算法
template <class RA>
class Cache
{
private:
	RA m_ra;
public:
	Cache() { }
	~Cache() { }
	void Replace() { m_ra.Replace(); }
};
           使用方式如下:
int main()
{
	Cache<Random_ReplaceAlgorithm> cache; //模板實參
	cache.Replace();
	return 0;
}