前言
當我們寫代碼時總會遇到一種情況就是我們會有很多的選擇,由此衍生出很多的if...else,或者case。比如我們根據(jù)學(xué)生的成績來評級,60分是及格,90分是優(yōu)秀,這就會用到很多if...else或者case。當然很多個算法集中在一個類的時候就會使得這個類變得臃腫,維護的成本也會加大。關(guān)于學(xué)生評級的例子,如果我們新增一種情況比如70分是一般,就需要修改算法的代碼,而且還是在一堆if...else或者case語句中添加一句。這顯然違背了開放封閉原則和單一職責(zé)原則。這一講我們就來將策略模式,來看看它是怎么解決如上所說的問題的。
1.策略模式簡介
策略模式定義
定義一系列的算法,把每一個算法封裝起來, 并且使它們可相互替換。策略模式模式使得算法可獨立于使用它的客戶而獨立變化。
策略模式UML圖
這里寫圖片描述
- Context:用來操作策略的上下文環(huán)境。
- Stragety:策略的抽象。
- ConcreteStragetyA、ConcreteStragetyB:具體的策略實現(xiàn)。
2.策略模式簡單實現(xiàn)
這回我們還舉武俠的例子,張無忌作為一個大俠會遇到很多的對手,如果每遇到一個對手都用自己最厲害的武功去應(yīng)戰(zhàn)這顯然是不明智的,于是張無忌想出了三種應(yīng)戰(zhàn)的策略分別對付三個實力層次的對手。
定義策略接口
策略接口有一個fighting的方法用于戰(zhàn)斗:
public interface FightingStrategy {
public void fighting();
}
具體策略實現(xiàn)
分別定義三個策略來實現(xiàn)策略接口,用來對付三個實力層次的對手:
public class WeakRivalStrategy implements FightingStrategy {
@Override
public void fighting() {
System.out.println("遇到了較弱的對手,張無忌使用太極劍");
}
}
public class CommonRivalStrategy implements FightingStrategy {
@Override
public void fighting() {
System.out.println("遇到了普通的對手,張無忌使用圣火令神功");
}
}
public class StrongRivalStrategy implements FightingStrategy {
@Override
public void fighting() {
System.out.println("遇到了強大的對手,張無忌使用乾坤大挪移");
}
}
實現(xiàn)環(huán)境類
環(huán)境類的構(gòu)造函數(shù)包含了策略類,通過傳進來不同的具體策略來調(diào)用不同策略的fighting方法:
public class Context {
private FightingStrategy fightingStrategy;
public Context(FightingStrategy fightingStrategy) {
this.fightingStrategy = fightingStrategy;
}
public void fighting(){
fightingStrategy.fighting();
}
}
客戶端調(diào)用
張無忌遇到了三個對手:宋青書、滅絕師太和成昆,他分別采用了不同的策略來應(yīng)戰(zhàn):
public class ZhangWuJi {
public static void main(String[] args) {
Context context;
//張無忌遇到對手宋青書,采用對弱的對手的策略
context = new Context(new WeakRivalStrategy());
context.fighting();
//張無忌遇到對手滅絕師太,采用對普通的對手的策略
context = new Context(new CommonRivalStrategy());
context.fighting();
//張無忌遇到對手成昆,采用對強勁的對手的策略
context = new Context(new StrongRivalStrategy());
context.fighting();
}
}
3.策略模式優(yōu)缺點和使用場景
優(yōu)點
- 策略模式提供了管理相關(guān)的算法族的辦法。策略類的等級結(jié)構(gòu)定義了一個算法或行為族。恰當使用繼承可以把公共的代碼轉(zhuǎn)移到父類里面,從而避免重復(fù)的代碼。
- 使用策略模式可以避免使用多重條件轉(zhuǎn)移語句。多重轉(zhuǎn)移語句不易維護,它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起,統(tǒng)統(tǒng)列在一個多重轉(zhuǎn)移語句里面,比使用繼承的辦法還要原始和落后。
缺點
- 客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時選擇恰當?shù)乃惴?。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
- 策略模式造成很多的策略類,每個具體策略類都會產(chǎn)生一個新類。有時候可以通過把依賴于環(huán)境的狀態(tài)保存到客戶端里面,而將策略類設(shè)計成可共享的,這樣策略類實例可以被不同客戶端使用。換言之,可以使用享元模式來減少對象的數(shù)量。
使用場景
- 對客戶隱藏具體策略(算法)的實現(xiàn)細節(jié),彼此完全獨立。
- 針對同一類型問題的多種處理方式,僅僅是具體行為有差別時。
- 一個類定義了很多行為,而且這些行為在這個類里的操作以多個條件語句的形式出現(xiàn)。策略模式將相關(guān)的條件分支移入它們各自的 Strategy 類中以代替這些條件語句。