策略模式的定義
策略模式(Strategy Pattern)是一種比較簡(jiǎn)單的模式,也叫政策模式(Policy Pattern)其定義如下:Define a family of algorithms each one , and make them interchangeable(定義一組算法,將每個(gè)算法都封裝起來(lái),并且使他們之間可以互換)
這個(gè)定義很清晰、明確,”定義一組算法“就是定義了3個(gè)計(jì)謀,”將每個(gè)算法封裝起來(lái)“,封裝類Context的作用,”使他們可以互換“,因?yàn)槎紝?shí)現(xiàn)的是相同的接口。

策略模式使用的是面向?qū)ο蟮睦^承和多態(tài)機(jī)制
?Context封裝角色:
它也叫做上下文角色,起承上啟下封裝作用,屏蔽高層模塊對(duì)策略、算法的直接訪問(wèn),封裝能存在著變化
?Strategy抽象策略角色:
策略、算法家族的抽象,通常為接口,定義每個(gè)策略或算法必須具有的方法和屬性。類圖中的
AlgorithmInterface是運(yùn)算法則+接口的意思。?ConcreteStrategy:
實(shí)現(xiàn)抽象策略中的操作,該類含有具體算法。
抽象的策略角色
是一個(gè)普通的接口。
public interface Strategy {
//策略模式的運(yùn)算法則
public void doSomething();
}
具體策略角色
具體策略角色也是非常普通的一個(gè)實(shí)現(xiàn)類,只要實(shí)現(xiàn)接口中的方法就可以
public class ConcreteStrategy1 implements Strategy{
@Override
public void doSomething() {
System.out.println("具體策略1的運(yùn)算法則");
}
}
public class ConcreteStrategy1 implements Strategy{
@Override
public void doSomething() {
System.out.println("具體策略1的運(yùn)算法則");
}
}
封裝角色
策略模式的重點(diǎn)就是封裝角色,它是借助了代理模式的思路,差別就是策略模式的封裝角色和被封裝的策略類不用是同一個(gè)接口,如果是同一個(gè)接口那就成為了代理模式
//封裝角色
public class Context {
//抽象策略
private Strategy strategy = null;
//構(gòu)造函數(shù)設(shè)置具體策略
public Context(Strategy _strategy){
this.strategy = _strategy;
}
//封裝后的策略方法
public void doAnything(){
this.strategy.doSomething();
}
}
高層模塊
知道要用哪個(gè)策略,產(chǎn)生出他的對(duì)象,然后放到封裝角色中
public class Client {
public static void main(String[] args) {
//聲明一個(gè)具體策略
Strategy strategy = new ConcreteStrategy1();
//聲明上下文對(duì)象
Context context = new Context(strategy);
//執(zhí)行封裝后的方法
context.doAnything();
}
}
策略模式的應(yīng)用
策略模式的優(yōu)點(diǎn):
?算法可以自由切換
這是策略模式本身定義,只要實(shí)現(xiàn)抽象類,他就成為策略家族的一個(gè)成員,通過(guò)封裝角色對(duì)其進(jìn)行封裝,保證對(duì)外提供”可自由切換的模式“的策略。
?避免使用多重條件判斷
可以由其他模塊決定采用何種策略,策略家族對(duì)外提供的訪問(wèn)接口就是封裝類,簡(jiǎn)化了操作,,同時(shí)避免了條件語(yǔ)句判斷。
?擴(kuò)展性良好
在現(xiàn)有系統(tǒng)中增加一個(gè)策略十分容易,只要實(shí)現(xiàn)接口就可以,其他都不用修改,類似于一個(gè)可反復(fù)拆卸的插件,也符合OCP原則(開(kāi)閉原則)
策略模式的缺點(diǎn):
?策略類數(shù)量多
每一個(gè)策略都是一個(gè)類,復(fù)用可能性很小,類的數(shù)量增多。
?所有策略都需要對(duì)外暴露
上層模塊必須知道有哪些策略,然后才能決定使用哪一個(gè)策略,這與迪米特法則是相違背的。我們可以使用其他的模式來(lái)修正這個(gè)缺點(diǎn),如工廠模式、代理模式、享元模式。
策略模式的使用場(chǎng)景:
?多個(gè)類只有在算法或行為上稍有不同的場(chǎng)景
?算符需要自由切換的場(chǎng)景
?需要屏蔽算法規(guī)則的場(chǎng)景
策略模式的注意事項(xiàng):
如果系統(tǒng)中的一個(gè)策略家族的具體策略數(shù)量超過(guò)4個(gè),則需要考慮使用混合模式,解決策略膨脹和對(duì)外暴露的問(wèn)題。
策略模式的擴(kuò)展
輸入3個(gè)參數(shù),進(jìn)行加減法運(yùn)算,參數(shù)中兩個(gè)是int型,剩下的一個(gè)參數(shù)是String類型的,只有”+“、”-“兩個(gè)符合可以選擇,不要考慮什么復(fù)雜校驗(yàn),進(jìn)行白箱測(cè)試,輸入的就是標(biāo)準(zhǔn)的int 類型和String類型。
枚舉策略
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;
}
};
String value = "";
// 定義成員值類型
private Calculator(String _value) {
this.value = _value;
}
// 獲取枚舉成員的值
public String getValue(){
return this.value;
}
// 聲明一個(gè)抽象函數(shù)
public abstract int exec(int a,int b);
}
為什么叫策略枚舉?首先它是一個(gè)枚舉類。策略呢?我們定義了一個(gè)抽象的方法exec(int a ,int b)然后在每個(gè)枚舉成員中進(jìn)行實(shí)現(xiàn),如果不實(shí)現(xiàn)就不能編譯。把原有定義在抽象策略中的方法移植到枚舉中,每個(gè)枚舉成員就成為一個(gè)具體策略
枚舉策略定義如下:
- 它是一個(gè)枚舉。
- 它是一個(gè)濃縮了的策略模式的枚舉。
public class Client {
public static void main(String[] args) {
int a = 1;
String symbol = "+";
int b = 2;
System.out.println(a+symbol+b+"="+Calculator.ADD.exec(a, b));
}
}