序言
情景設計
設計一款模擬鴨子的遊戲,遊戲中出現各種鴨子,一邊游泳戲水,一邊呱呱叫。所用的鴨子會呱呱叫,也會游泳,所以基類負責實現。但是每一款鴨子外觀不一樣,所以這是抽象行爲。由子類實現。
前期設計及思路
根據情景的設計,首先我們想到這是一些列的鴨子,便會想到利用繼承的手段,進行解決。其UML圖型爲:
後續設計:需要讓有的鴨子飛,有的鴨子不能飛。後續設計
問題:
1、在調用中是通過抽象類進行操作的,所以新功能在超類有所體現,
但是下載超類中實現,就所有的鴨子會飛。
2、在超類中是飛的行爲是抽象函數,這樣每個子類都要實現,代碼重寫太複雜。
3、用接口,只讓飛的鴨子繼承實現飛的行爲接口,這樣在超類中進行初始化接口。
4、但是用接口後,讓飛的行爲進行修改,那個每個子類中飛的行爲也要修改,這樣改動也是很大。
經過分析,利用組合的原則,將變化部分進行提取,封裝一個新類,所以我們見fly這個行爲提取出來,行爲上肯定是接口,同時這個接口由行爲類實現,而不是具體鴨子類實現,這樣就實現策略模式。
這裏的接口就是所謂的概念,針對“利用接口編程”,關鍵在於多態。利用多態,程序可以對超類進行操作,根據實際情況執行到真正行爲,將行爲和對象進行解耦。
在程序運行時就是針對超類編程,超類編程就是接口和抽象類。
圖爲:
所以這樣針對新行爲,我們重新定義個接口,然後實現這個接口,在調用時初始化接口。
其中主要的代碼爲:
//關鍵這是超類,必定是抽象類
public abstract class Duck
{
protected IFlyBehavior flyBehavior;
protected QuackBehavior quackBehavior;
public virtual void Quack()
{
throw new System.NotImplementedException();
}
//當然這些行爲也可通過接口,但是這游泳鴨子都會,所以超類直接實現
public virtual void Swim()
{
throw new System.NotImplementedException();
}
//抽象函數,子類必須實現,意味子類這個行爲不同
public abstract void DisPlay();
public virtual void performFly()
{
//通過接口執行fly行爲,要尋找接口在那初始化
flyBehavior.fly();
}
}
//duck的子類,其中初始化了接口
public class BlueDuck : Duck
{
public BlueDuck()
{
//初始化接口,在用BlueDuck初始化Duck時,接口也被初始化了。
flyBehavior = new FlyWithWings();
}
public override void DisPlay()
{
throw new System.NotImplementedException();
}
}
總結
當你將兩個類結合起來使用時,如同本例,這就是組合。這種做法的不同是在於行爲不是繼承而來,單獨通過行爲類和接口進行實現。
策略模式定義了算法族,分別封裝起來,讓他們之間可以相互替換,使算法的變化獨立於使用算法的客戶。