在我們需要實現(xiàn)一個功能的時候王带,可以有多種算法來實現(xiàn)的時候抑党,我們可以使用if...else或者case來選擇對應(yīng)的算法來實現(xiàn)功能遂蛀。但是如果又有新的算法添加進來的時候娜遵,我們不得不重新修改之前的代碼。
那么如何才能夠?qū)ζ溥M行優(yōu)雅的編碼而不會在有變化的時候去修改我們的原來的代碼呢礁蔗?
定義
策略模式定義了一系列的算法觉义,它們具有共同的一些通性,通過這個通性紐帶關(guān)聯(lián)起來浴井,在使用算法的時候可以相互切換晒骇。策略模式將算法的本身實現(xiàn)和使用算法隔離開來,這樣對于算法的變化從而讓調(diào)用者無法感知磺浙。
結(jié)構(gòu)
strategy.png
策略模式涉及到3個角色:
- 使用環(huán)境(客戶端):持有抽象策略的引用洪囤,對外提供了切換策略的方法
- 抽象策略:可以是接口也可以是抽象類,視具體情況而定
- 具體策略:實現(xiàn)了策略中的算法定義屠缭,對具體算法的封裝
以一個排序為例
在我們對一組數(shù)據(jù)排序的時候箍鼓,可以有多種算法選擇:冒泡、選擇呵曹、插入等等款咖。
抽象策略
public interface ISort {
void sort(int[] source);
}
具體策略
-
冒泡排序
public class BubbleSort implements ISort { @Override public void sort(int[] source) { int temp = 0; for (int i = 0; i < source.length - 1; i++) { for (int j = 0; j < source.length - 1 - i; j++) { if (source[j] > source[j + 1]) { temp = source[j]; source[j] = source[j + 1]; source[j + 1] = temp; } } } } }
-
插入排序
public class InsertSort implements ISort { @Override public void sort(int[] source) { for (int i = 1; i < source.length; i++) { int temp = source[i]; int j = i - 1; for (; j >= 0 && source[j] > temp; j--) { //將大于temp的值整體后移一個單位 source[j + 1] = source[j]; } source[j + 1] = temp; } } }
-
選擇排序
public class ChooseSort implements ISort { @Override public void sort(int[] source) { for(int i=0;i<source.length;i++){ int lowIndex = i; for(int j=i+1;j<source.length;j++){ if(source[j]<source[lowIndex]){ lowIndex = j; } } //將當前第一個元素與它后面序列中的最小的一個 元素交換何暮,也就是將最小的元素放在最前端 int temp = source[i]; source[i] = source[lowIndex]; source[lowIndex] = temp; } } }
Context
public class SortContext {
private ISort sort;
public void setSort(ISort sort) {
this.sort = sort;
}
public void func(int[] source) {
System.out.println("排序前的數(shù)據(jù):" + Arrays.toString(source));
sort.sort(source);
System.out.println("排序后的數(shù)據(jù): " + Arrays.toString(source));
}
public static void main(String[] args) {
int[] source = {56,2,345,12,9,7,56};
int[] source1 = source.clone();
int[] source2 = source.clone();
int[] source3 = source.clone();
SortContext sortContext = new SortContext();
sortContext.setSort(new BubbleSort());
sortContext.func(source1);
System.out.println("-------------------------------------");
sortContext.setSort(new ChooseSort());
sortContext.func(source2);
System.out.println("-------------------------------------");
sortContext.setSort(new InsertSort());
sortContext.func(source3);
}
}
結(jié)果:
排序前的數(shù)據(jù):[56, 2, 345, 12, 9, 7, 56]
排序后的數(shù)據(jù): [2, 7, 9, 12, 56, 56, 345]
-------------------------------------
排序前的數(shù)據(jù):[56, 2, 345, 12, 9, 7, 56]
排序后的數(shù)據(jù): [2, 7, 9, 12, 56, 56, 345]
-------------------------------------
排序前的數(shù)據(jù):[56, 2, 345, 12, 9, 7, 56]
排序后的數(shù)據(jù): [2, 7, 9, 12, 56, 56, 345]
可以看到,我們使用不同的策略算法來達到了我們目的铐殃,在我們的客戶端并不清楚它們之間的區(qū)別海洼。策略模式的核心就是如何去調(diào)度這些算法而不是如何實現(xiàn)這些算法。
策略模式的優(yōu)點是可以動態(tài)的切換算法來改變客戶端的行為富腊。但是它的缺點也是比較明顯的坏逢,客戶端需要知道所有的策略實現(xiàn),如果策略比較多赘被,那么不僅僅是類增加了是整,客戶端管理起來也是一個麻煩事。