介紹
在項目開發(fā)中,經(jīng)常會碰到需要根據(jù)不同的條件采用不同的算法止潮,但是這些不同的算法又有些類似。例如商城下單中的打折功能(打八折钞楼、五折、一折)袄琳,滿減功能等等询件。
地圖中根據(jù)采用不同的出行方式計算時間燃乍、金額等等,如下圖宛琅,不同的出行方式使用不同的算法計算需要花費的時間和最短的行駛距離刻蟹。
結(jié)構(gòu)圖
那這些不同的行為,我們可以把它們封裝成不同的算法嘿辟,根據(jù)用戶選擇的不同采用不同的算法舆瘪,這種可以采用策略模式來實現(xiàn)他們。
案例
這次的案例就采用壓縮文件的案例红伦,用戶選擇不同的壓縮策略后臺相應采用不同的壓縮算法進行壓縮英古。
**算法接口類Algorithm **
public interface Algorithm {
void compress();
}
**算法接口類實現(xiàn)類RarAlgorithm **
public class RarAlgorithm implements Algorithm {
@Override
public void compress() {
System.out.println("Rar壓縮文件。昙读。召调。");
}
}
**算法接口類實現(xiàn)類ZipAlgorithm **
public class ZipAlgorithm implements Algorithm {
@Override
public void compress() {
System.out.println("Zip壓縮文件。蛮浑。唠叛。");
}
}
算法上下文類AlgorithmContext
public class AlgorithmContext {
private Algorithm algorithm;
public AlgorithmContext(Algorithm algorithm) {
this.algorithm = algorithm;
}
public void handle(){
algorithm.compress();
}
}
業(yè)務類
public class Client {
public static void main(String[] args) {
//String type = "RarAlgorithm";
String type = "ZipAlgorithm";
AlgorithmContext algorithmContext = null;
switch (type) {
case "ZipAlgorithm":
algorithmContext = new AlgorithmContext(new ZipAlgorithm());
break;
case "RarAlgorithm":
algorithmContext = new AlgorithmContext(new RarAlgorithm());
break;
default:
break;
}
if (algorithmContext != null) {
algorithmContext.handle();
}
}
}
上面就是策略模式的代碼,其實還是有優(yōu)化的地方沮稚,例如下面這一段代碼可以交給算法上下文類AlgorithmContext來決定艺沼,讓業(yè)務類只接觸AlgorithmContext,而不用接觸到具體的算法類蕴掏,真正的實現(xiàn)解耦澳厢。而下面的代碼可以挪到AlgorithmContext中使用簡單工廠模式實現(xiàn)。
switch (type) {
case "ZipAlgorithm":
algorithmContext = new AlgorithmContext(new ZipAlgorithm());
break;
case "RarAlgorithm":
algorithmContext = new AlgorithmContext(new RarAlgorithm());
break;
default:
break;
}
簡單工廠模式和策略模式結(jié)合
修改后的AlgorithmContext類
public class AlgorithmContext {
private Algorithm algorithm;
//使用簡單工廠模式
public AlgorithmContext(String type) {
switch (type) {
case "ZipAlgorithm":
algorithm = new ZipAlgorithm();
break;
case "RarAlgorithm":
algorithm = new RarAlgorithm();
break;
default:
algorithm = new ZipAlgorithm();
break;
}
}
public void handle(){
algorithm.compress();
}
}
業(yè)務類
public class Client {
public static void main(String[] args) {
//String type = "RarAlgorithm";
String type = "ZipAlgorithm";
//使用簡單工廠模式
AlgorithmContext algorithmContext = new AlgorithmContext(type);
algorithmContext.handle();
}
}
正常來說這篇博文到這里結(jié)束了囚似,但是仔細想想剩拢,如果增加了一個壓縮算法,那么switch重是不是還要增加一個條件饶唤?那么有沒有辦法解決徐伐?答案是有的,java可以使用反射技術(shù).
使用反射來替換條件判斷
修改后的AlgorithmContext類
public class AlgorithmContext {
private Algorithm algorithm;
//使用簡單工廠模式
public AlgorithmContext(String type) {
try {
//簡單實現(xiàn)(可用配置文件來配置type對應的類全稱)
Class clazz = Class.forName("com.dp.strategy.algorithm.impl."+type);
algorithm = (Algorithm) clazz.newInstance();
} catch (Exception e) {
algorithm = new ZipAlgorithm();
e.printStackTrace();
}
}
public void handle(){
algorithm.compress();
}
}
上面只是提供個反射思路來替換條件判斷而已募狂,正常項目開發(fā)不會用這種方式办素,更多的會采用配置文件的方式來獲取對應的類,就像spring的配置bean一樣祸穷,就是下面這種方式性穿,有興趣可以研究研究
<bean id="..." class="..." destroy-method="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
總結(jié)
總的來說,策略模式就是將算法從業(yè)務邏輯中抽取出來雷滚,然后將選擇權(quán)交給用戶需曾,這樣在一定程度上提高了系統(tǒng)的靈活性。策略模式主要優(yōu)點在于對“開閉原則”的完美支持,在不修改原有系統(tǒng)的基礎(chǔ)上可以更換算法或者增加新的算法呆万,它很好地管理算法族商源,提高了代碼的復用性,是一種替換繼承谋减,避免多重條件轉(zhuǎn)移語句的實現(xiàn)方式牡彻;其缺點在于客戶端必須知道所有的策略類,并理解其區(qū)別出爹,同時在一定程度上增加了系統(tǒng)中類的個數(shù)庄吼,可能會存在很多策略類。
那么什么時候可以使用策略模式呢严就?
在一個系統(tǒng)里面有許多類总寻,它們之間的區(qū)別僅在于它們的行為,使用策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為盈蛮;一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種废菱;避免使用難以維護的多重條件選擇語句;希望在具體策略類中封裝算法和與相關(guān)的數(shù)據(jù)結(jié)構(gòu)抖誉。
這篇博文相關(guān)的代碼
https://github.com/rainbowda/Design-Pattern/tree/master/dp-common/src/main/java/com/dp/strategy