1.概述
該模式定義了一系列算法,并將每個(gè)算法封裝起來,使它們可以相互替換,且算法的變化不會(huì)影響使用算法的客戶。策略模式屬于對象行為模式,它通過對算法進(jìn)行封裝,把使用算法的責(zé)任和算法的實(shí)現(xiàn)分割開來,并委派給不同的對象對這些算法進(jìn)行管理。
2.結(jié)構(gòu)
策略模式的主要角色如下:
- 抽象策略(Strategy)類:這是一個(gè)抽象角色,通常由一個(gè)接口或抽象類實(shí)現(xiàn)。此角色給出所有的具體策略類所需的接口。
- 具體策略(Concrete Strategy)類:實(shí)現(xiàn)了抽象策略定義的接口,提供具體的算法實(shí)現(xiàn)或行為。
- 環(huán)境(Context)類:持有一個(gè)策略類的引用,最終給客戶端調(diào)用。
3.案例
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/26 19:56
* 抽象策略類
*/
public interface Strategy {
void show();
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/26 19:59
* 具體策略類
*/
public class StrategyA implements Strategy{
@Override
public void show() {
System.out.println("策略1");
}
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/26 19:59
* 具體策略類
*/
public class StrategyB implements Strategy{
@Override
public void show() {
System.out.println("策略2");
}
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/26 19:59
* 具體策略類
*/
public class StrategyC implements Strategy{
@Override
public void show() {
System.out.println("策略3");
}
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/26 20:00
* 促銷員(環(huán)境類)
*/
public class SalesMan {
// 聚合策略類對象
private Strategy strategy;
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public SalesMan(Strategy strategy) {
this.strategy = strategy;
}
// 由促銷員展示促銷活動(dòng)給用戶
public void salesManShow() {
strategy.show();
}
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/26 20:02
*/
public class Client {
public static void main(String[] args) {
SalesMan salesMan = new SalesMan(new StrategyA());
salesMan.salesManShow();
salesMan.setStrategy(new StrategyC());
salesMan.salesManShow();
}
}
4.優(yōu)缺點(diǎn)
1,優(yōu)點(diǎn):
-
策略類之間可以自由切換
由于策略類都實(shí)現(xiàn)同一個(gè)接口,所以使它們之間可以自由切換。
-
易于擴(kuò)展
增加一個(gè)新的策略只需要添加一個(gè)具體的策略類即可,基本不需要改變原有的代碼,符合“開閉原則“
-
避免使用多重條件選擇語句(if else),充分體現(xiàn)面向?qū)ο笤O(shè)計(jì)思想。
2,缺點(diǎn):
- 客戶端必須知道所有的策略類,并自行決定使用哪一個(gè)策略類。
- 策略模式將造成產(chǎn)生很多策略類,可以通過使用享元模式在一定程度上減少對象的數(shù)量。
5.使用場景
- 一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種時(shí),可將每個(gè)算法封裝到策略類中。
- 一個(gè)類定義了多種行為,并且這些行為在這個(gè)類的操作中以多個(gè)條件語句的形式出現(xiàn),可將每個(gè)條件分支移入它們各自的策略類中以代替這些條件語句。
- 系統(tǒng)中各算法彼此完全獨(dú)立,且要求對客戶隱藏具體算法的實(shí)現(xiàn)細(xì)節(jié)時(shí)。
- 系統(tǒng)要求使用算法的客戶不應(yīng)該知道其操作的數(shù)據(jù)時(shí),可使用策略模式來隱藏與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)。
- 多個(gè)類只區(qū)別在表現(xiàn)行為不同,可以使用策略模式,在運(yùn)行時(shí)動(dòng)態(tài)選擇具體要執(zhí)行的行為。
6.JDK源碼解析
Comparator
中的策略模式。在Arrays類中有一個(gè) sort()
方法,如下:
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就是一個(gè)環(huán)境角色類,這個(gè)sort方法可以傳一個(gè)新策略讓Arrays根據(jù)這個(gè)策略來進(jìn)行排序。就比如下面的測試類。
public class demo {
public static void main(String[] args) {
Integer[] data = {12, 2, 3, 2, 4, 5, 1};
// 實(shí)現(xiàn)降序排序
Arrays.sort(data, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1]
}
}
這里我們在調(diào)用Arrays的sort方法時(shí),第二個(gè)參數(shù)傳遞的是Comparator接口的子實(shí)現(xiàn)類對象。所以Comparator充當(dāng)?shù)氖浅橄蟛呗越巧?,而具體的子實(shí)現(xiàn)類充當(dāng)?shù)氖蔷唧w策略角色。環(huán)境角色類(Arrays)應(yīng)該持有抽象策略的引用來調(diào)用。那么,Arrays類的sort方法到底有沒有使用Comparator子實(shí)現(xiàn)類中的 compare()
方法嗎?讓我們繼續(xù)查看TimSort類的 sort()
方法,代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-705350.html
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;
}
}
上面的代碼中最終會(huì)跑到 countRunAndMakeAscending()
這個(gè)方法中。我們可以看見,只用了compare方法,所以在調(diào)用Arrays.sort方法只傳具體compare重寫方法的類對象就行,這也是Comparator接口中必須要子類實(shí)現(xiàn)的一個(gè)方法。文章來源地址http://www.zghlxwxcb.cn/news/detail-705350.html
到了這里,關(guān)于Gof23設(shè)計(jì)模式之策略模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!