設計模式之策略模式(STRATEGY),設計模式strategy
1.適用性
當存在以下情況時使用STRATEGY模式
a.許多相關的類僅僅是行為有異。“策略”提供了一種用多個行為中的一個行為來配置一個類的方法。
b.需要使用一個演算法的不同變體。例如,你可能會定義一些反映不同的空間/時間權衡的演算法。當這些變體實現為一個演算法的類層次時,可以使用原則模式。
c.演算法使用客戶不應該知道的資料。可以使用原則模式以避免暴露複雜的、與演算法相關的資料結構。
d.一個類定義了多種行為,並且這些行為在這個類的操作中以多個條件陳述式的形式出現。將相關的條件分支移入它們各自的Strategy類中以替代這些條件陳述式。
2.參與者
Strategy(策略): 定義所有支援的演算法的公用介面。Context使用這個介面來調用某種ConcreteStrategy定義的演算法。
ConcreteStrategy(具體策略):以Strategy介面實現某種具體演算法。
Context(上下文):用一個ConcreteStategy對象來配置;維護一個對Strategy對象的引用;可定義一個介面讓Strategy訪問它的資料。
3.優缺點
優點:
a.相關演算法系列:Strategy類層次為Context定義了一系列的可供重用的演算法或行為。繼承有助於析取演算法中的公用的功能。
b.一個替代繼承的方法:可以直接產生一個Context的子類,從而給它以不同的行為。但是,這會將行為寫入程式碼到Context中,而將演算法的實現和Context的實現混合起來,使得Context難以理解、維護和擴充,而且還不能動態改變演算法。
c.消除了一些條件陳述式:沒有使用strategy模式的代碼很有可能會被設計成在一個類中,使用if判斷條件執行相應的策略。
d.實現的選擇:用戶端可以根據要求從不同的策略中進行選擇。
缺點:
a.Strategy和Context之間的通訊開銷: 無論各個ConcreteStrategy實現的演算法是簡單還是複雜,他們都會共用Strategy定義的介面。因此很可能某些ConcreteStrategy不會都用到所有通過這個介面傳遞給他們的資訊。簡單的ConcreteStrategy可能不會使用其中的任何資訊,這就意味著有時Context會建立和初始化一些永遠不會用到的參數。如果存在這樣的問題,那麼將需要在Strategy和Context之間進行緊密的耦合。
b.增加了對象的數目
4.執行個體
package strategy;/** * Description: 策略介面類 * * @author * @version 1.0 * @since 2017-08-02 5:46 PM */public interface Strategy { void algorithmInterface();}
package strategy;/** * Description: 具體策略A * * @author * @version 1.0 * @since 2017-08-02 5:47 PM */public class ConcreteStrategyA implements Strategy { @Override public void algorithmInterface() { System.out.println("策略A執行"); }}
package strategy;/** * Description: 具體策略B * * @author * @version 1.0 * @since 2017-08-02 5:48 PM */public class ConcreteStrategyB implements Strategy { @Override public void algorithmInterface() { System.out.println("策略B執行"); }}
package strategy;/** * Description: 具體策略C * * @author * @version 1.0 * @since 2017-08-02 5:49 PM */public class ConcreteStrategyC implements Strategy { @Override public void algorithmInterface() { System.out.println("策略C執行"); }}
package strategy;/** * Description: 上下文配置類 * * @author yunqiangdi * @version 1.0 * @since 2017-08-02 5:49 PM */public class Context { //持有策略介面的引用 private Strategy strategy; /** * 用其中某個策略初始化上下文 * @param strategy 具體的策略類 */ public Context(Strategy strategy) { this.strategy = strategy; } /** * 進行策略的具體執行 */ public void operator() { strategy.algorithmInterface(); }}
package strategy;/** * Description: 策略測試類別 * * @author yunqiangdi * @version 1.0 * @since 2017-08-02 5:55 PM */public class StrategyTest { public static void main(String[] args) { Strategy strategy = new ConcreteStrategyA(); Context ctx = new Context(strategy); ctx.operator(); }}
第二種表示策略的方式為使用匿名內部類表示策略(這種也可以把匿名內部類當作一個函數對象)。
package strategy.example2;/** * @author koou * @version 1.0 * @since 2017-08-05 下午 13:26 */public interface Strategy<T> { /** * 策略介面 * @param t 策略執行 */ <T> void process(T t);}
package strategy.example2;/** * @author koou * @version 1.0 * @since 2017-08-05 下午 13:27 */public class StrategyProcess { /** * @param t 策略的執行對象 * @param strategy 具體策略 */ public static <T> void apply(T t, Strategy<T> strategy) { strategy.process(t); }}
package strategy.example2;import java.util.Arrays;/** * @author koou * @version 1.0 * @since 2017-08-05 下午 13:30 */public class StrategyTest { public static void main(String[] args) { int[] iarray = {1, 2, 3, 4, 5}; //對int數組進行策略操作,修改數組第一個數字為9097 StrategyProcess.apply(iarray, new Strategy<int[]>() { public <T> void process(T t) { int[] temparray = (int[]) t; if (temparray.length > 1) { temparray[0] = 9097; } } }); System.out.println(Arrays.toString(iarray)); }}
輸出為:
[9097, 2, 3, 4, 5]
由匿名內部類每次執行的時候會建立一個新的執行個體,如果它被重複執行,考慮將函數Object Storage Service到一個私人的靜態final域中。
package strategy.example3;import java.io.Serializable;import java.util.Comparator;/** * @author koou * @version 1.0 * @since 2017-08-05 下午 17:03 */public class Host { private static class StrLenCmp implements Comparator<String>, Serializable { public int compare(String o1, String o2) { return o1.length() - o2.length(); } } //具體的策略 public static final Comparator<String> STRING_LEN_COMPARATOR = new StrLenCmp();}
package strategy.example3;import java.util.Arrays;/** * @author koou * @version 1.0 * @since 2017-08-05 下午 17:09 */public class StrategyTest { public static void main(String[] args) { String[] strArray = {"I", "am", "sk", "I"}; Arrays.sort(strArray, Host.STRING_LEN_COMPARATOR); System.out.println(Arrays.toString(strArray)); }}
測試結果:[I, I, am, sk] 查看評論