前言:
現在電商已經成為我們生活中不可或缺的購物渠道,同時各大商家會針對不同的時間做出不同的折扣,這在我們看來就是一種營銷手段,也是一種策略,今天我們就來講講JDK中的策略模式是怎么樣的。
一、定義
定義了算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化不會影響到使用算法的用戶。可以用來消除大量的if...else結構。
二、適用場景
1、系統有很多類,它們的區別僅在於它們的行為不同
2、一個系統需要動態的在幾種算法中選擇一種
在這里稍微理解一下,策略模式其實和工廠模式很像,不過工廠模式是創建型的,是接收到指令來去創建相應的工廠,而策略模式是傳入一個創建好的策略來實現具體行為。重點理解行為和算法。其實只不過是我們根據不同業務場景做出的不同反應,拿淘寶來說,雙十一的促銷活動力度最大,可能打到5折,而女王節一般只打到7折。針對這兩種不同的對象,就有兩種不同的行為或者不同的算法,在客戶端調用時,可以直接傳入對應的策略就能做出相應的行為。下面我們來具體看一下策略模式在JDK中的應用
三、Comparator中的策略模式
我們先來認清,策略模式中到底需要什么角色:
1、抽象策略角色
負責定義通常由一個接口或抽象類實現。此角色給出所有的具體策略類所需的接口。
2、策略實現類
不同的類實現具體不同的算法。
3、環境角色類
里面持有抽象策略角色的引用,然后客戶端可以由具體的方法傳不同參數或實現類進去得到不同算法。
我們現在直接看Arrays這個類
public class Arrays{ public static <T> void sort(T[] a, Comparator<? super T> c) { if (c == null) { sort(a); } else { if (LegacyMergeSort.userRequested) legacyMergeSort(a, c); else TimSort.sort(a, 0, a.length, c, null, 0, 0); } } }
Arrays就是一個環境角色類,這個sort方法你可以傳一個新策略讓Arrays根據這個方法來進行排序。就比如下面的測試類。
public class Test1 { public static void main(String[] args) { Integer []data ={12,2,3,2,4,5,1}; // 實現降序排序,返回-1放左邊,1放右邊,0保持不變 Arrays.sort(data, (str1, str2) -> { if (str1.compareTo(str2) > 0) { return -1; } else { return 1; } }); System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1] } }
這里是直接用lambda表達式進行重寫Comparator接口中的compare方法,可以認為這里的lambda表達式就是具體的算法,可見Comparator充當的就是抽象策略角色。我上面說過,環境角色類應該持有抽象策略的引用來調用,Arrays類中的sort方法是直接傳Comparator接口,如果是有自己的compare方法那么就會進入到下面這個方法
class TimSort<T> { static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c, T[] work, int workBase, int workLen) { assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; int nRemaining = hi - lo; if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges if (nRemaining < MIN_MERGE) { int initRunLen = countRunAndMakeAscending(a, lo, hi, c); binarySort(a, lo, hi, lo + initRunLen, c); return; } private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi, Comparator<? super T> c) { assert lo < hi; int runHi = lo + 1; if (runHi == hi) return 1; // Find end of run, and reverse range if descending if (c.compare(a[runHi++], a[lo]) < 0) { // Descending while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0) runHi++; reverseRange(a, lo, runHi); } else { // Ascending while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0) runHi++; } return runHi - lo; } }
這里多說一下,上面的代碼中最終會跑到countRunAndMakeAscending這個方法中。我們可以看見,只用了compare方法,所以在調用Arrays.sort方法只傳具體compare重寫方法的類就行,這也是Comparator接口中必須要子類實現的一個方法。
四、總結
其實學了這么多模式,你會發現這些模式的大體很相似,但是細究起來又不相似。策略模式是很容易和工廠模式弄混淆的。策略模式的核心就是不同的行為對應不同的算法,而工廠更多的是生產不同的產品,給產品規定好的參數和返回類型。