策略模式
</br>
前言
很多人在閱讀第三方框架(例如Retrofit)的時候,不太懂或者比較吃力,是因為我們?nèi)鄙僖恍懘a的思維,看代碼的設(shè)計的模式,今天,小菜我說下對策略模式的理解
</br>
介紹
- 專業(yè)說法:定義了一系列的算法,并將每個算法封裝起來,而且使它們還可以相互替換,策略模式讓算法獨立于使用它的客戶而獨立變化
- 例子說法:假設(shè),今天,我要為舍友煮一道菜,小菜我買了一塊豬肉,但是,舍友開心的時候,是喜歡吃紅燒肉,則我要做紅燒肉;難過的時候,是喜歡吃燜豬肉,則我要做燜豬肉:
1.難過(策略)->做紅燒肉(算法)
2.開心(策略)->做燜豬肉(算法)
</br>
改善前的代碼
/**
* Created by Jenchar on 2016/7/30.
*/
public class Meat {
public static final String HAPPY="開心";
public static final String SAD="難過";
public static final String REDMEAT="紅燒肉";
public static final String BRAISEMEAT="燜豬肉";
public static void main(String[] args) {
Meat meat=new Meat();
meat.chooseFood(SAD,BRAISEMEAT);
}
private void chooseFood(String fellings,String type) {
if(fellings.equals(HAPPY)){
codeRedMeat(type);
}else{
cookBraiseMeat(type);
}
}
private void cookBraiseMeat(String meat) {
System.out.println("他"+HAPPY+"的時候,"+"我要為他煮"+meat);
}
private void codeRedMeat(String meat) {
System.out.println("他"+SAD+"的時候,"+"我要為他煮"+meat);
}
}
輸出結(jié)果:
他難過的時候,我要為他煮紅燒肉
分析:
Meat類很明顯的問題是并不是單一職責(zé)(簡單來說,就是一個類只有一種功能),首先它承擔(dān)了做紅燒肉和做燜豬肉的職責(zé),另一個問題就是通過if-else的形式來判斷做哪一種。小菜想,當(dāng)我舍友他發(fā)神經(jīng)病,興奮的時候,會喜歡吃炸豬肉呢,那么我就需要在Meat類中增加一個方法去做炸豬肉,并且要在 chooseFood(String fellings,String type)方法里又增加一個判斷,代碼如下:
</br>
/**
* Created by Jenchar on 2016/7/30.
*/
public class Meat {
public static final String HAPPY="開心";
public static final String SAD="難過";
public static final String REDMEAT="紅燒肉";
public static final String BRAISEMEAT="燜豬肉";
/**
* 增加的
*/
public static final String EXCITED="興奮";
public static final String FLYINGMEAT="炸豬肉";
public static void main(String[] args) {
Meat meat=new Meat();
meat.chooseFood(EXCITED,FLYINGMEAT);
}
private void chooseFood(String fellings,String type) {
if(fellings.equals(HAPPY)){
codeRedMeat(type);
}else if(fellings.equals(SAD)){
cookBraiseMeat(type);
/**
* 增加的
*/
}else if(fellings.equals(EXCITED)){
cookFlyingMeat(type);
}
}
/**
*增加的
*/
private void cookFlyingMeat(String type) {
System.out.println("他"+EXCITED+"的時候,"+"我要為他煮"+type);
}
private void cookBraiseMeat(String meat) {
System.out.println("他"+HAPPY+"的時候,"+"我要為他煮"+meat);
}
private void codeRedMeat(String meat) {
System.out.println("他"+SAD+"的時候,"+"我要為他煮"+meat);
}
}
輸出結(jié)果:
他興奮的時候,我要為他煮炸豬肉
再分析:
看看 chooseFood(String fellings,String type)這個方法,現(xiàn)在代碼是不是很亂了,各種if-else語句纏繞在其中?當(dāng)小菜的舍友,因為精神分裂,又想吃另外一種,那么,我又要在chooseFood增加if-else。當(dāng)if-else語句多了,就會很容易看錯,寫錯,而且,代碼臃腫,小的項目,小的類雖然過得去,但是到了大的項目,必然會很亂,難以維護(hù)。所以,因這種情況 ,小菜我開始引進(jìn)了一種設(shè)計模式,“策略模式”
</br>
改善后的代碼
首先小菜我需要定義一個抽象的做肉接口,命名CookStrategy,代碼如下:
/**
* 做肉的接品
*/
public interface CookStrategy {
/**
* 根據(jù)舍友的情感來做肉
* @param feelings
*/
void cook(String feelings);
}
接著對于做紅燒肉還是燜豬肉,小菜我覺得應(yīng)該都有一個獨立的做肉策略類,這些類都實現(xiàn)上面說的CookStrategy接口,代碼如下:
CookRedMeat.java:
/**
* 做紅燒肉的類
*/
public class CookRedMeat implements CookStrategy{
public static final String REDMEAT="紅燒肉";
/**
* 開始做他喜歡的紅燒肉
* @param feelings
*/
@Override
public void cook(String feelings) {
System.out.println("他"+feelings+"的時候,"+"我要為他煮"+REDMEAT);
}
}
CookBraiseMeat.java:
/**
* 做燜肉的類
*/
public class CookBraiseMeat implements CookStrategy {
public static final String BRAISEMEAT="燜豬肉";
@Override
/**
* 開始做他喜歡的燜豬肉
* @param feelings
*/
public void cook(String feelings) {
System.out.println("他"+feelings+"的時候,"+"我要為他煮"+BRAISEMEAT);
}
}
最后,我們再創(chuàng)建一個的Meat類。
public class Meat {
public static final String HAPPY="開心";
public static final String SAD="難過";
/**
* 持有CookStrategy對象
*/
private CookStrategy mCookStrategy;
public static void main(String[] args) {
Meat meat=new Meat();
meat.setCookStrategy(new CookBraiseMeat());
meat.cookFood(SAD);
}
/**
* 把子類的引用賦值到mCookStrategy,就可以調(diào)用子類的方法。
* @param cookStrategy
*/
private void setCookStrategy(CookStrategy cookStrategy) {
mCookStrategy=cookStrategy;
}
private void cookFood(String feelings){
mCookStrategy.cook(feelings);
}
}
最后分析
通過改善前后的代碼,可以看出:
- 前者:通過if-else解決問題,代碼臃腫,邏輯復(fù)雜,難以升級與維護(hù),沒有結(jié)構(gòu)可言
- 后者:通過建立接口,將不同的策略構(gòu)建成一個具體的策略實現(xiàn) ,通過不同的策略實現(xiàn)算法替換,從而更好地增加擴(kuò)展性,直觀性。
</br>
結(jié)論與使用場景
- 針對同一類型的問題,多種處理,僅僅是具體為行有差別(做紅燒肉,做燜豬肉)
- 出現(xiàn)同一抽象類有多個子類,雖然使用if-else或者switch-case來選擇子類的(根據(jù)舍友的心情來做肉)
- 需要安全地封裝多種同一類型的操作時(做紅燒肉,做燜豬肉這些操作時)
</br>
喜歡我的朋友,可以與我一起討論問題,我也是學(xué)習(xí)者,希望與大學(xué)一起學(xué)習(xí)。