策略模式(strategy pattern)

 

策略模式在java集合中的TreeSet和TreeMap中獲得了很好的應用,咱們能夠實現Comparator接口實現Compareto()方法來定義本身的排序規則,而後經過TreeSet,TreeMap構造方法傳入實現該接口的實例,map中的順序就會是咱們自定義的順序。咱們能夠徹底定義本身的規則,用之極爲方便。那麼,什麼是策略模式呢?java

 

策略模式定義:定義一組算法,將每一個算法都封裝起來,而且使它們之間能夠轉換。策略模式使這些算法在客戶端調用時可以互不影響的變化。算法

 

策略模式組成:編程

        1.抽象的策略角色:策略類,一般由一個抽象類或者接口實現。數組

        2.具體的策略角色:包裝了相關的算法和行爲。數據結構

        3.環境角色:持有一個策略類的引用,以便最終給客戶端調用。ide

 

策略模式的設計原則:ui

       1. 封裝變化this

       2.使用接口編程spa

 

策略模式的實現:設計

       1.將每一組算法封裝到具備共同接口的獨立類中,這樣不一樣的策略能夠相互替換

           2.算法能夠在不影響客戶端的狀況下發生變化,把行爲和環境分開。

         3.環境類負責維持和查詢行爲類,各類算法在具體策略中提供

 

看文字看蒙了,舉一個具體的例子吧,舉什麼例子呢?想到咱們數據結構中的各類排序,什麼冒泡排序,快速排序,堆排序...,他們完成的功能都是同樣的,只是排序算法不一樣而已。咱們就能夠當作是排序的不一樣策略。

 

首先定義咱們的抽象策略:

/** * 抽象的策略類 * @author * */
public interface Strategy { public void sort(int[] array); }
View Code

定義具體的策略,這裏實現了三種策略,分別是快速排序,堆排序,歸併排序。

快速排序策略代碼:

public class QuickSort implements Strategy{ @Override public void sort(int[] array) { qpSort(array,0,array.length - 1); } private void qpSort(int array[], int low, int high) { int pos = qkPass(array, low, high); //產生中間第一個肯定的數

        if (low < high) { qpSort(array, low, pos - 1);//左邊
            qpSort(array, pos + 1, high);//右邊
 } } private  int qkPass(int a[], int low, int high) { int x = a[low]; while (low < high) { while (low < high && a[high] > x) { high--; } if (low < high) { a[low] = a[high]; low++; } while (low < high && a[low] < x) { low++; } if (low < high) { a[high] = a[low]; high--; } } a[low] = x; return low; } }
View Code

 

堆排序策略代碼:

public class HeapSort implements Strategy { @Override public void sort(int[] array) { heapSort(array,array.length); } private void heapSort(int a[], int length) { crtHeap(a, length); // 建立大根堆

        for (int i = length - 1; i > 0; i--) { int b = a[0]; a[0] = a[i]; // 堆頂跟堆尾互換
 a[i] = b; sift(a, 0, i - 1); // 使得r[0...i-1]變成堆
 } } /** * 創建初堆 * * @param a * 爲帶排序的數組 * @param length * 爲數組長度 */
    private void crtHeap(int a[], int length) { int n = length - 1; // 建出堆,從第 n/2 個記錄開始進行堆篩選
        for (int i = n / 2; i >= 0; i--) { sift(a, i, n); } } /** * * @param r * 數組 * @param k * 表示以r[k]爲根的徹底二叉樹,調整r[k],使得r[k...m]知足大根堆的性質 * @param m * 堆尾元素下標 */
    private void sift(int r[], int k, int m) { int temp = r[k]; // 暫存根記錄

        int i = k; // 記錄初始根的下標

        int j = i * 2 + 1; // 根的左孩子,由於下標從0開始

        while (j <= m) { // 若是存在右子樹,且右子樹根的關鍵字大,則沿右分支篩選,不然沿左分支篩選。由於目的是找一個最大的元素
            if (j < m && r[j] < r[j + 1]) { j = j + 1; } if (temp >= r[j]) { break; // 結束篩選
 } else { r[i] = r[j]; // 上移
                i = j; // 重新定義根下標
                j = j * 2 + 1;// 繼續篩選
 } } r[i] = temp; // 將r[k]移動到適當的位置
 } }
View Code

 

歸併排序策略代碼:

public class MergeSort implements Strategy{ @Override public void sort(int[] array) { int[] temp = new int[array.length]; mSort(array,0,array.length - 1, temp); } /** * * @param r1 等待排序數組 * @param low * @param high * @param r3 將r1排序後的結果放在r3中 r1[low...high],r3[low...high] */
    private void mSort(int r1[],int low,int high, int r3[]){ if(low  < high) { int mid = (low + high) /2; //歸併排序中 拆,合要一塊兒進行
 mSort(r1,low,mid,r3); mSort(r1,mid+1,high,r3); merge(r1,low, mid, high, r3); } } private void merge(int r1[],int low, int mid, int high, int r2[]){ int i = low; int j = mid + 1; int k = 0; while(i <=mid && j <= high){ if(r1[i] <= r1[j]){ r2[k] = r1[i]; i++; } else{ r2[k] = r1[j]; j++; } k++; } while(i <= mid){ r2[k] = r1[i]; i++; k++; } while(j <= high){ r2[k] = r1[j]; j++; k++; } for(int m = 0; m < k;m++){ r1[low + m] = r2[m]; } } }
View Code

 

定義環境類:

public class Environment { private Strategy strategy; //策略類的引用
    
    public Environment(Strategy strategy){ this.strategy = strategy; } //用於設置不一樣的策略
    public void setStrategy(Strategy strategy){ this.strategy = strategy; } //實現排序的功能
    public void sort(int array[]){ strategy.sort(array); } }
View Code

 

最後定義客戶端類:

public class Client { public static void main(String[] args) { int[] array1 = new int[]{48,62,35,77,55,14,35,98}; int[] array2 = new int[]{48,62,35,77,55,14,35,98}; int[] array3 = new int[]{48,62,35,77,55,14,35,98}; //使用堆排序策略
        Environment env = new Environment(new HeapSort()); env.sort(array1); System.out.println("使用堆排序array1:"); print(array1); //使用快速排序策略
        env.setStrategy(new QuickSort()); env.sort(array2); System.out.println("使用快速排序array2:"); print(array2); //使用歸併排序策略
        env.setStrategy(new MergeSort()); env.sort(array3); System.out.println("使用歸併排序array3:"); print(array3); } static void print(int[] array){ for(int i = 0; i < array.length; i++){ System.out.print(array[i] + "\t"); } System.out.println(); System.out.println("---------------------------------"); } }
View Code

 

運行結果以下所示:

咱們使用不一樣的排序策略分別對三個數組排序的功能已經實現了,程序很是靈活,咱們想用什麼策略來實現排序能夠本身決定(經過environment.serStrategy(XXX)方法)。

程序中Environment類根本不知道也不用管排序究竟是怎麼實現的,它只是持有一個具體策略類的引用,而後調用具體策略類的方法。

 

策略模式用着很方便,可是自己也有缺點:

    1.客戶端必須知道全部的策略類,並自行決定使用哪一種策略類。

         2.形成不少的策略類,每個不一樣的策略都須要一個策略類來實現。

 

對於第一點很明顯,咱們客戶端(client類)在使用策略時必須知道具體的策略類是什麼,environment.serStrategy(XXX)方法也須要知道。

對於第二點,定義了3中策略,就有3個策略類,若是策略不少的話,類也會不少。

 

參考資料:聖思園教學視頻

相關文章
相關標籤/搜索