策略模式
</br>
前言
很多人在閱讀第三方框架(例如Retrofit)的時(shí)候犬庇,不太懂或者比較吃力喳篇,是因?yàn)槲覀內(nèi)鄙僖恍懘a的思維敌买,看代碼的設(shè)計(jì)的模式藤乙,今天猜揪,小菜我說下對(duì)策略模式的理解
</br>
介紹
- 專業(yè)說法:定義了一系列的算法,并將每個(gè)算法封裝起來坛梁,而且使它們還可以相互替換而姐,策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化
- 例子說法:假設(shè),今天划咐,我要為舍友煮一道菜拴念,小菜我買了一塊豬肉,但是褐缠,舍友開心的時(shí)候政鼠,是喜歡吃紅燒肉,則我要做紅燒肉队魏;難過的時(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+"的時(shí)候器躏,"+"我要為他煮"+meat);
}
private void codeRedMeat(String meat) {
System.out.println("他"+SAD+"的時(shí)候俐载,"+"我要為他煮"+meat);
}
}
輸出結(jié)果:
他難過的時(shí)候,我要為他煮紅燒肉
分析:
Meat類很明顯的問題是并不是單一職責(zé)(簡(jiǎn)單來說登失,就是一個(gè)類只有一種功能)遏佣,首先它承擔(dān)了做紅燒肉和做燜豬肉的職責(zé),另一個(gè)問題就是通過if-else的形式來判斷做哪一種揽浙。小菜想状婶,當(dāng)我舍友他發(fā)神經(jīng)病,興奮的時(shí)候馅巷,會(huì)喜歡吃炸豬肉呢膛虫,那么我就需要在Meat類中增加一個(gè)方法去做炸豬肉,并且要在 chooseFood(String fellings,String type)方法里又增加一個(gè)判斷钓猬,代碼如下:
</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+"的時(shí)候稍刀,"+"我要為他煮"+type);
}
private void cookBraiseMeat(String meat) {
System.out.println("他"+HAPPY+"的時(shí)候,"+"我要為他煮"+meat);
}
private void codeRedMeat(String meat) {
System.out.println("他"+SAD+"的時(shí)候,"+"我要為他煮"+meat);
}
}
輸出結(jié)果:
他興奮的時(shí)候账月,我要為他煮炸豬肉
再分析:
看看 chooseFood(String fellings,String type)這個(gè)方法综膀,現(xiàn)在代碼是不是很亂了,各種if-else語句纏繞在其中局齿?當(dāng)小菜的舍友剧劝,因?yàn)榫穹至眩窒氤粤硗庖环N抓歼,那么讥此,我又要在chooseFood增加if-else。當(dāng)if-else語句多了谣妻,就會(huì)很容易看錯(cuò)萄喳,寫錯(cuò),而且蹋半,代碼臃腫取胎,小的項(xiàng)目,小的類雖然過得去湃窍,但是到了大的項(xiàng)目,必然會(huì)很亂匪傍,難以維護(hù)您市。所以,因這種情況 役衡,小菜我開始引進(jìn)了一種設(shè)計(jì)模式茵休,“策略模式”
</br>
改善后的代碼
首先小菜我需要定義一個(gè)抽象的做肉接口,命名CookStrategy,代碼如下:
/**
* 做肉的接品
*/
public interface CookStrategy {
/**
* 根據(jù)舍友的情感來做肉
* @param feelings
*/
void cook(String feelings);
}
接著對(duì)于做紅燒肉還是燜豬肉手蝎,小菜我覺得應(yīng)該都有一個(gè)獨(dú)立的做肉策略類榕莺,這些類都實(shí)現(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+"的時(shí)候棵介,"+"我要為他煮"+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+"的時(shí)候钉鸯,"+"我要為他煮"+BRAISEMEAT);
}
}
最后,我們?cè)賱?chuàng)建一個(gè)的Meat類邮辽。
public class Meat {
public static final String HAPPY="開心";
public static final String SAD="難過";
/**
* 持有CookStrategy對(duì)象
*/
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ù)雜,難以升級(jí)與維護(hù)揣云,沒有結(jié)構(gòu)可言
- 后者:通過建立接口捕儒,將不同的策略構(gòu)建成一個(gè)具體的策略實(shí)現(xiàn) ,通過不同的策略實(shí)現(xiàn)算法替換,從而更好地增加擴(kuò)展性邓夕,直觀性刘莹。
</br>
結(jié)論與使用場(chǎng)景
- 針對(duì)同一類型的問題阎毅,多種處理,僅僅是具體為行有差別(做紅燒肉栋猖,做燜豬肉)
- 出現(xiàn)同一抽象類有多個(gè)子類净薛,雖然使用if-else或者switch-case來選擇子類的(根據(jù)舍友的心情來做肉)
- 需要安全地封裝多種同一類型的操作時(shí)(做紅燒肉,做燜豬肉這些操作時(shí))
</br>
喜歡我的朋友蒲拉,可以與我一起討論問題肃拜,我也是學(xué)習(xí)者,希望與大學(xué)一起學(xué)習(xí)雌团。