策略模式得益于按照開閉原則進(jìn)行設(shè)計,各個具體算法按照單一職責(zé)原則設(shè)計; 提高了代碼的復(fù)用性,對客戶隱藏具體策略 (算法) 的實現(xiàn)細(xì)節(jié),彼此完全獨立,擴(kuò)展其余不受影響;避免if-else 或 switch 分支語句判斷;其缺點在于客戶端必須知道所有的策略類,增加了系統(tǒng)中類的個數(shù)。

一、前言
策略模式可能是在工作中使用最多的,也是在面試中最常提到的,代碼重構(gòu)和優(yōu)化的必備!
小編之前也是一直說,其實沒有真正的實戰(zhàn);最近有了機(jī)會實戰(zhàn)了一下,來分享一下使用心得和在企業(yè)級的使用!
二、策略模式
1、什么是策略模式
策略模式,英文全稱是 Strategy Design Pattern。在 GoF 的《設(shè)計模式》一書中,它是這樣定義的:
定義一族算法類,將每個算法分別封裝起來,讓它們可以互相替換。策略模式可以使算法的變化獨立于使用它們的客戶端(這里的客戶端代指使用算法的代碼)。
2、策略模式結(jié)構(gòu)組成
- Strategy:抽象策略類,一般為接口或者策略類。
- ConcreteStrategy:具體算法實現(xiàn)策略類。
- Context:環(huán)境或者上下文類,用于統(tǒng)一執(zhí)行具體策略。
其實以上三部分用白話文來解釋就是:
需要一個接口和策略進(jìn)行規(guī)范和約束接口和方法,這時需要一些具體的實現(xiàn)算法類去繼承或者實現(xiàn)剛剛的接口和策略,最后通過一個環(huán)境或者上下文,也可以叫做工廠根據(jù)類型進(jìn)行調(diào)用具體的算法!
3、使用場景
- 避免冗長的 if-else 或 switch 分支判斷
- 需要動態(tài)地在幾種算法中選擇一種
- 對客戶隱藏具體策略 (算法) 的實現(xiàn)細(xì)節(jié),彼此完全獨立,擴(kuò)展其余不受影響
具體場景一般為:
- 支付方式選擇
- 打折、滿減方式選擇
- 根據(jù)類型調(diào)用不同的系統(tǒng)
4、優(yōu)缺點
優(yōu)點:
- 擴(kuò)展性好
- 符合開閉原則
- 符合單一職責(zé)原則
- 可讀性好
- 便于維護(hù)
- 避免多層判斷
缺點:
三、策略模式實戰(zhàn)
1、實戰(zhàn)例子
今天小編根據(jù)春夏秋冬四季需要做不同的事情來演示一下策略模式的使用方案:
需求是:
如果是春天,就要去放風(fēng)箏
如果是夏天,就要去游泳
如果是秋天,就要去看楓葉
如果是冬天,就要去打雪仗
沒有使用策略模式的話,肯定就是
if-if else進(jìn)行實現(xiàn)!
下面就帶大家體會一下具體使用哈??!
2、策略接口
/**
* 四季策略
* @author wangzhenjun
* @date 2022/12/1 9:30
*/
public interface SeasonsStrategy {
/**
* 根據(jù)季節(jié)去執(zhí)行不同的方案
* @param seasons
* @return
*/
String execute(String seasons);
}
3、春季具體實現(xiàn)
/**
* 春季具體實現(xiàn)
* @author wangzhenjun
* @date 2022/12/1 9:34
*/
// 指定容器的名稱,不指定默認(rèn)為類名稱首字母小寫
@Component("spring")
public class SpringStrategy implements SeasonsStrategy{
@Override
public String execute(String seasons) {
return seasons + "來了!我們一起去放風(fēng)箏吧!";
}
}
4、夏季具體實現(xiàn)
/**
* 夏季具體實現(xiàn)
* @author wangzhenjun
* @date 2022/12/1 9:34
*/
// 指定容器的名稱,不指定默認(rèn)為類名稱首字母小寫
@Component("summer")
public class SummerStrategy implements SeasonsStrategy{
@Override
public String execute(String seasons) {
return seasons + "來了!我們一起去游泳吧!";
}
}
5、秋季具體實現(xiàn)
/**
* 秋季具體實現(xiàn)
* @author wangzhenjun
* @date 2022/12/1 9:34
*/
// 指定容器的名稱,不指定默認(rèn)為類名稱首字母小寫
@Component("autumn")
public class AutumnStrategy implements SeasonsStrategy{
@Override
public String execute(String seasons) {
return seasons + "來了!我們一起去放看楓葉吧!";
}
}
6、冬季具體實現(xiàn)
/**
* 冬季具體實現(xiàn)
* @author wangzhenjun
* @date 2022/12/1 9:34
*/
// 指定容器的名稱,不指定默認(rèn)為類名稱首字母小寫
@Component("winter")
public class WinterStrategy implements SeasonsStrategy{
@Override
public String execute(String seasons) {
return seasons + "來了!我們一起去打雪仗吧!";
}
}
7、上下文工廠實現(xiàn)
private Map<String, SeasonsStrategy> seasonsMap;這是最重要的,很多時候我們都知道怎么進(jìn)行策略和實現(xiàn)怎么寫,不知道怎么統(tǒng)一去放進(jìn)去,來進(jìn)行調(diào)用,可以自己放在map中。當(dāng)然spring已經(jīng)給我們組裝好了,只要按需調(diào)用即可!
核心:Spring會自動將Strategy接口的實現(xiàn)類注入到這個Map中,key為bean id,value值則為對應(yīng)的策略實現(xiàn)類!
/**
* 環(huán)境或者上下文類,用于統(tǒng)一執(zhí)行具體策略
* @author wangzhenjun
* @date 2022/12/1 9:56
*/
@Component
public class SeasonsFactory {
/**
* Spring會自動將Strategy接口的實現(xiàn)類注入到這個Map中,key為bean id,value值則為對應(yīng)的策略實現(xiàn)類
*/
@Autowired
private Map<String, SeasonsStrategy> seasonsMap;
/**
* 處理四季統(tǒng)一入口方法
* @param seasons
* @param beanName
* @return
*/
public String handle(String seasons,String beanName){
// 根據(jù)bean的名稱獲取對應(yīng)的算法處理類
SeasonsStrategy seasonsStrategy = seasonsMap.get(beanName);
String execute = seasonsStrategy.execute(seasons);
return execute;
}
}
8、controller處理
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private SeasonsFactory seasonsFactory;
@GetMapping("/strategyTest/{seasons}/{beanName}")
public Result strategyTest(@PathVariable("seasons") String seasons,@PathVariable("beanName") String beanName){
String handle = seasonsFactory.handle(seasons, beanName);
return Result.success(handle);
}
}
9、測試
??http://localhost:8087/test/strategyTest/春天/spring。??

??http://localhost:8087/test/strategyTest/夏天/summer。??

四、總結(jié)
在策略模式中定義了一系列算法,將每一個算法封裝起來,并讓它們可以相互替換,互不影響。
策略模式得益于按照開閉原則進(jìn)行設(shè)計,各個具體算法按照單一職責(zé)原則設(shè)計; 提高了代碼的復(fù)用性,對客戶隱藏具體策略 (算法) 的實現(xiàn)細(xì)節(jié),彼此完全獨立,擴(kuò)展其余不受影響;避免if-else 或 switch 分支語句判斷;其缺點在于客戶端必須知道所有的策略類,增加了系統(tǒng)中類的個數(shù)。
在日常開發(fā)一般用于消除多重判斷,有時候不要為了用設(shè)計模式而用設(shè)計模式,一定要結(jié)合業(yè)務(wù)場景,過度設(shè)計也是很致命的!!