前面我們談了簡單工廠模式,下面我們談一下策略模式。
策略模式定義了一系列的算法,並將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立於使用它的客戶而獨立變化。
它的優點有:
1、 提供了一種替代繼承的方法,而且既保持了繼承的優點(代碼重用)還比繼承更靈活(算法獨立,可以任意擴展)。
2、 避免程序中使用多重條件轉移語句,使系統更靈活,並易於擴展。
3、 遵守大部分GRASP原則和常用設計原則,高內聚、低偶合。
缺點:
因爲每個具體策略類都會產生一個新類,所以會增加系統需要維護的類的數量
我們以商場收銀來說明一下這個模式。
商場收銀軟件需求很簡單,營業員根據客戶所購買商品的單價和數量,向客戶收費。
也許有些人會這麼想,這個很簡單,接受用戶輸入的的單價和數量,把他們相乘不就可以了嘛。當然,。,那當然可以。那如果商場對某些商品進行打折活動呢。也許你會說,那還不簡單,讓用戶輸入打幾折不就行了嘛。計算總價時在原來的基礎上乘以折扣就是客戶的收費了。也許這個時候,你想到了封裝,抽象,或者用我們以前的簡單工廠模式來解決這個問題。代碼如下:
1;我們先寫一個現金收費抽象類。
public abstract class CashSuper {
public abstract double acceptCash(double money);
}
2:正常收費子類,繼承現金收費抽象類:
public class CashNormal extends CashSuper {
public double acceptCash(double money){
return money;
}
}
3:打折收費子類,繼承現金收費抽象類
public class CashRebate extends CashSuper {
private double moneyRebate=0.0;//折扣
@Override
public double acceptCash(double money) {
// TODO Auto-generated method stub
return money*moneyRebate;
}
public CashRebate(String moneyRebate){
this.moneyRebate=Double.parseDouble(moneyRebate);
}
}
4:返利收費子類,如果客戶滿300返100
public class CashReturn extends CashSuper {
private double moneyCondition=0;//返利條件
private double moneyReturn=0;//返利
public CashReturn(String moneyCondition,String moneyReturn ){
this.moneyCondition=Double.parseDouble(moneyCondition);
this.moneyReturn=Double.parseDouble(moneyReturn);
}
public double acceptCash(double money){
double result=money;
if(money>=moneyCondition)
result=money-Math.floor(money/moneyCondition)*moneyReturn;
return result;
}
}
5:現金收費工廠類:
public class CashFactory {
public static CashSuper createCashAccept(int type ){
CashSuper cs=null;
switch(type){
case 1:
//1表示正常收費
cs=new CashNormal();
break;
case 2:
//滿300返100
CashReturn cr1=new CashReturn("300","100");
cs=cr1;
break;
case 3:
//打8折
CashRebate cr2=new CashRebate("0.8");
cs=cr2;
break;
}
return cs;
}
}
6:測試類主要實例化工廠類,接受單價和數量,還有折扣和返利。
我們想想這是最好的辦法嗎?我們前面講過,簡單工廠模式雖然也能解決這類問題,但是我們知道這個模式只是解決對象的創建問題。而商場收銀軟件也許有可能會經常更改打折和返利,那我們是不是都要改動工廠呢?仔細想想,它打折和返利,只是算法的更改。爲什麼我們不用策略模式呢?
策略模式定義了算法家族,分別封裝起來 ,讓他們之間可以互相替換,此模式讓算法的變化,不會影響到使用算法的客戶。
下面我們用策略模式和簡單工廠的結合解決這個問題:
原來寫的CashSuper,CashNormal,CashRebate,CashReturn都不用改了,我們再加一個類:
1:cashContext類,用一個ConcreteStrategy來配置,維護一個對Strategy對象的引用。
public class CashContext {
private CashSuper cs=null;
public CashContext(int type){
switch(type){
case 1:
//正常收費
CashNormal cs1=new CashNormal();
cs=cs1;
break;
case 2:
//滿300返回100
CashReturn cr2=new CashReturn("300","100");
cs=cr2;
break;
case 3:
CashRebate cr3=new CashRebate("0.8");
cs=cr3;
break;
}
}
public double GetResult(double money){
return cs.acceptCash(money);
}
}
這樣就可以了,其他的任務交給客戶端就行了。