深入理解Java設(shè)計(jì)模式之策略模式
一、什么是策略模式
策略模式定義了一系列算法,并將每個(gè)算法封裝起來(lái),使他們可以相互替換,且算法的變化不會(huì)影響到使用算法的客戶。需要設(shè)計(jì)一個(gè)接口,為一系列實(shí)現(xiàn)類(lèi)提供統(tǒng)一的方法,多個(gè)實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)該接口,設(shè)計(jì)一個(gè)抽象類(lèi)(可有可無(wú),屬于輔助類(lèi)),提供輔助函數(shù)。
策略模式定義和封裝了一系列的算法,它們是可以相互替換的,也就是說(shuō)它們具有共性,而它們的共性就體現(xiàn)在策略接口的行為上,另外為了達(dá)到最后一句話的目的,也就是說(shuō)讓算法獨(dú)立于使用它的客戶而獨(dú)立變化,我們需要讓客戶端依賴于策略接口。
一種很簡(jiǎn)單的解釋?zhuān)谖覀兊拈_(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到大量的if...else或者switch...case語(yǔ)句,當(dāng)這些語(yǔ)句在開(kāi)發(fā)中只是為了起到分流作用,這些分流和業(yè)務(wù)邏輯無(wú)關(guān),那么這個(gè)時(shí)候就可以考慮用策略模式。
二、策略模式的結(jié)構(gòu)

這個(gè)模式涉及到三個(gè)角色:
上下文環(huán)境(Context)角色:持有一個(gè)Strategy的引用。
抽象策略(Strategy)角色:這是一個(gè)抽象角色,通常由一個(gè)接口或抽象類(lèi)實(shí)現(xiàn)。此角色給出所有的具體策略類(lèi)所需的接口。
具體策略(ConcreteStrategy)角色:包裝了相關(guān)的算法或行為
三、策略模式的應(yīng)用場(chǎng)景
舉一個(gè)例子,商場(chǎng)搞促銷(xiāo)--打8折,滿200送50,滿1000送禮物,這種促銷(xiāo)就是策略。
再舉一個(gè)例子,dota里面的戰(zhàn)術(shù),玩命四保一,三偽核體系,推進(jìn)體系,大招流體系等,這些戰(zhàn)術(shù)都是一種策略。
應(yīng)用場(chǎng)景:
1、 多個(gè)類(lèi)只區(qū)別在表現(xiàn)行為不同,可以使用Strategy模式,在運(yùn)行時(shí)動(dòng)態(tài)選擇具體要執(zhí)行的行為。
2、 需要在不同情況下使用不同的策略(算法),或者策略還可能在未來(lái)用其它方式來(lái)實(shí)現(xiàn)。
3、 對(duì)客戶隱藏具體策略(算法)的實(shí)現(xiàn)細(xì)節(jié),彼此完全獨(dú)立。
四、策略模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1、結(jié)構(gòu)清晰,把策略分離成一個(gè)個(gè)單獨(dú)的類(lèi)「替換了傳統(tǒng)的 if else」2、代碼耦合度降低,安全性提高「各個(gè)策略的細(xì)節(jié)被屏蔽」
缺點(diǎn):
1、客戶端必須要知道所有的策略類(lèi),否則你不知道該使用那個(gè)策略,所以策略模式適用于提前知道所有策略的情況下2、策略類(lèi)數(shù)量增多(每一個(gè)策略類(lèi)復(fù)用性很小,如果需要增加算法,就只能新增類(lèi))五、策略模式和簡(jiǎn)單工廠模式的異同
在上篇文章已經(jīng)提過(guò)了,傳送地址:深入理解設(shè)計(jì)模式(二):簡(jiǎn)單工廠模式
六、策略模式的實(shí)現(xiàn)
Strategy類(lèi),定義所有支持的算法的公共接口
//Strategy類(lèi),定義所有支持的算法的公共接口
abstract class Strategy
{
//算法方法
public abstract void AlgorithmInterface();
}
oncreteStrategy,封裝了具體的算法或行為,繼承于Strategy
//算法A
class ConcreteStrategyA : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine("算法A的實(shí)現(xiàn)");
}
}
//算法B
class ConcreteStrategyB : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine("算法B的實(shí)現(xiàn)");
}
}
//算法C
class ConcreteStrategyC : Strategy
{
public override void AlgorithmInterface()
{
Console.WriteLine("算法C的實(shí)現(xiàn)");
}
}
Context,用一個(gè)ConcreteStrategy來(lái)配置,維護(hù)一個(gè)對(duì)Strategy對(duì)象的引用
//Context,用一個(gè)ConcreteStrategy來(lái)配置,維護(hù)一個(gè)對(duì)Strategy對(duì)象的引用
class Context
{
Strategy Strategy;
public Context(Strategy Strategy)
{
this.Strategy = Strategy;
}
//上下文接口
public void ContextInterface()
{
Strategy.AlgorithmInterface();
}
}
客戶端代碼
static void Main(string[] args)
{
Context Context;
Context = new Context(new ConcreteStrategyA());
Context.ContextInterface();
Context = new Context(new ConcreteStrategyB());
Context.ContextInterface();
Context = new Context(new ConcreteStrategyC());
Context.ContextInterface();
Console.Read();
}
七、策略模式和簡(jiǎn)單工廠模式的結(jié)合
改造后的Context
class Context
{
Strategy Strategy=null;
public Context(string type)
{
switch (type)
{
case "A":
ConcreteStrategyA A = new ConcreteStrategyA();
Strategy = A;
break;
case "B":
ConcreteStrategyB B = new ConcreteStrategyB();
Strategy = B;
break;
case "C":
ConcreteStrategyC C = new ConcreteStrategyC();
Strategy = C;
break;
}
}
//上下文接口
public void ContextInterface()
{
Strategy.AlgorithmInterface();
}
}
改造后的客戶端代碼
static void Main(string[] args)
{
Context Context = new Context("這里是相應(yīng)的算法類(lèi)型字符串");
Context.ContextInterface();
Console.Read();
}
對(duì)比下改造前后的區(qū)別不難看出,改造前客戶端需要認(rèn)識(shí)兩個(gè)類(lèi),Context和ConcreteStrategy。而策略模式和簡(jiǎn)單工廠模式結(jié)合后,客戶端只需要認(rèn)識(shí)一個(gè)類(lèi)Context,降低了耦合性。
八、策略枚舉的實(shí)現(xiàn)
我們可以使用枚舉在一個(gè)類(lèi)中實(shí)現(xiàn)以上所有的功能及三種不同的角色,下面看看怎么通過(guò)枚舉來(lái)實(shí)現(xiàn)策略模式
public enum Calculator
{ ADD("+") {
public int exec(int a, int b) {
return a+b;
}
},
SUB("-") {
public int exec(int a, int b) {
return a-b;
}
};
public abstract int exec(int a, int b);
//運(yùn)算符
private String value = "";
private Calculator(String value)
{
this.value = value;
}
public String getValue()
{
return value;
}
}
在枚舉類(lèi)中,定義的抽象方法就像當(dāng)時(shí)之前的接口,每一個(gè)枚舉ADD SUB相當(dāng)是一個(gè)具體的實(shí)現(xiàn)類(lèi)(策略角色),而整個(gè)枚舉類(lèi)就是策略的分裝角色。
這是從網(wǎng)上copy的代碼,本人不怎么喜歡這么寫(xiě),總感覺(jué)違背了代碼規(guī)范。
九、總結(jié)
策略模式,實(shí)質(zhì)就是封裝了一些算法,讓算法可以互相替換,用戶可以自由選擇這些算法進(jìn)行操作。策略模式本身理解起來(lái)沒(méi)什么難點(diǎn),但是在實(shí)際應(yīng)用中其本身主要結(jié)合工廠模式一起使用。
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Graceful Response 構(gòu)建 Spring Boot 響應(yīng)
Graceful Response是一個(gè)Spring Boot技術(shù)棧下的優(yōu)雅響應(yīng)處理器,提供一站式統(tǒng)一返回值封裝、全局異常處理、自定義異常錯(cuò)誤碼等功能,本文介紹Graceful Response 構(gòu)建 Spring Boot 下優(yōu)雅的響應(yīng)處理,感興趣的朋友一起看看吧2024-01-01
SpringBoot項(xiàng)目速度提升之延遲初始化(Lazy Initialization)詳解
延遲初始化(Lazy?Initialization)是一種在需要時(shí)才創(chuàng)建或加載對(duì)象的策略,以減少啟動(dòng)時(shí)間和資源消耗,本文就來(lái)講講延遲初始化的具體使用吧2023-05-05
Struts2單選按鈕詳解及枚舉類(lèi)型的轉(zhuǎn)換代碼示例
這篇文章主要介紹了Struts2單選按鈕詳解及枚舉類(lèi)型的轉(zhuǎn)換代碼示例,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02
Java實(shí)現(xiàn)按照大小寫(xiě)字母順序排序的方法
這篇文章主要介紹了Java實(shí)現(xiàn)按照大小寫(xiě)字母順序排序的方法,涉及java數(shù)組遍歷、編碼轉(zhuǎn)換、判斷等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
SpringMVC源碼解析之消息轉(zhuǎn)換器HttpMessageConverter
本篇文章主要介紹了SpringMVC源碼解析之消息轉(zhuǎn)換器HttpMessageConverter ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
Java中關(guān)于二叉樹(shù)的概念以及搜索二叉樹(shù)詳解
二叉樹(shù)是一種很有用的非線性結(jié)構(gòu),日常的開(kāi)發(fā)中常會(huì)用到,關(guān)于二叉樹(shù)的概念以及搜索二叉樹(shù)本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
SpringCloud項(xiàng)目中Feign組件添加請(qǐng)求頭所遇到的坑及解決
這篇文章主要介紹了SpringCloud項(xiàng)目中Feign組件添加請(qǐng)求頭所遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04

