Java中的策略模式


策略模式

策略模式的用意是針對一組算法,將每一個算法封裝到具有共同接口的獨立類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響到客戶端的情況下發生變化。

策略模式的結構

策略模式是對算法的包裝,是把使用算法的責任和算法本身分開。策略模式通常是把一系列的算法包裝到一系列的策略類里面,作為一個抽象策略類的子類。

策略模式涉及到三個角色:

1、環境角色

持有一個策略Strategy的引用

2、抽象策略角色

這是一個抽象角色,通常由一個接口或抽象類實現,此角色給出所有具體策略類所需的接口

3、具體策略角色

包裝了相關算法或行為

策略模式實際應用場景-容錯恢復機制

        容錯恢復機制是應用程序開發中非常常見的功能。那么什么是容錯恢復呢?簡單點說就是:程序運行的時候,正常情況下應該按照某種方式來做,如果按照某種方式來做發生錯誤的話,系統並不會崩潰,也不會就此不能繼續向下運行了,而是有容忍出錯的能力,不但能容忍程序運行出現錯誤,還提供出現錯誤后的備用方案,也就是恢復機制,來代替正常執行的功能,使程序繼續向下運行。
        舉個實際點的例子吧,比如在一個系統中,所有對系統的操作都要有日志記錄,而且這個日志還需要有管理界面,這種情況下通常會把日志記錄在數據庫里面,方便后續的管理,但是在記錄日志到數據庫的時候,可能會發生錯誤,比如暫時連不上數據庫了,那就先記錄在文件里面,然后在合適的時候把文件中的記錄再轉錄到數據庫中。
        對於這樣的功能的設計,就可以采用策略模式,把日志記錄到數據庫和日志記錄到文件當作兩種記錄日志的策略,然后在運行期間根據需要進行動態的切換。

示例

1.定義日志策略接口

1 public interface LogStrategy {
2 
3     public void log(String msg);
4 
5 }

2.實現日志策略接口

1)記錄到數據庫

1 public class DbLog implements LogStrategy{
2 
3     public void log(String msg) {     
4 
5        System.out.println("現在把 '"+msg+"' 記錄到數據庫中");
6 
7     }
8 
9 }

2)記錄到文件

1 public class FileLog implements LogStrategy{
2 
3     public void log(String msg) {
4 
5        System.out.println("現在把 '"+msg+"' 記錄到文件中");
6 
7     }
8 
9 }

3)接下來定義使用這些策略的上下文,注意這次是在上下文里面實現具體策略算法的選擇,所以不需要客戶端來指定具體的策略算法了,示例代碼如下:

 1 public class LogContext {
 2     
 3     public void log(String msg) {    
 4         
 5         LogStrategy strategy = new DbLog();
 6         try {
 7             strategy .log(msg);
 8         } catch(Exception e) {
 9              // 出錯,記錄到文件
10              strategy = new FileLog();
11              strategy.log(msg);  
12         }    
13     }
14 }

4.小結

通過上面的示例,會看到策略模式的一種簡單應用,也順便了解一下基本的容錯恢復機制的設計和實現。在實際的應用中,需要設計容錯恢復的系統一般要求都比較高,應用也會比較復雜,但是基本的思路是差不多的。

Java中的策略接口-Comparator接口

比方說Collections里面有一個sort方法,因為集合里面的元素有可能是復合對象,復合對象並不像基本數據類型,可以根據大小排序,復合對象怎么排序呢?基於這個問題考慮,Java要求如果定義的復合對象要有排序的功能,就自行實現Comparable接口或Comparator接口,看一下sort帶Comparator的重載方法:

1 public static <T> void sort(List<T> list, Comparator<? super T> c) {
2     Object[] a = list.toArray();
3     Arrays.sort(a, (Comparator)c);
4     ListIterator i = list.listIterator();
5     for (int j=0; j<a.length; j++) {
6         i.next();
7         i.set(a[j]);
8     }
9 }

看一下第3行:

1 public static <T> void sort(T[] a, Comparator<? super T> c) {
2     T[] aux = (T[])a.clone();
3         if (c==null)
4             mergeSort(aux, a, 0, a.length, 0);
5         else
6             mergeSort(aux, a, 0, a.length, 0, c);
7 }

再看一下第6行:

 1 private static void mergeSort(Object[] src,
 2                   Object[] dest,
 3                   int low, int high, int off,
 4                   Comparator c) {
 5     int length = high - low;
 6 
 7     // Insertion sort on smallest arrays
 8     if (length < INSERTIONSORT_THRESHOLD) {
 9         for (int i=low; i<high; i++)
10         for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
11             swap(dest, j, j-1);
12         return;
13     }
14 
15         // Recursively sort halves of dest into src
16         int destLow  = low;
17         int destHigh = high;
18         low  += off;
19         high += off;
20         int mid = (low + high) >>> 1;
21         mergeSort(dest, src, low, mid, -off, c);
22         mergeSort(dest, src, mid, high, -off, c);
23 
24         // If list is already sorted, just copy from src to dest.  This is an
25         // optimization that results in faster sorts for nearly ordered lists.
26         if (c.compare(src[mid-1], src[mid]) <= 0) {
27            System.arraycopy(src, low, dest, destLow, length);
28            return;
29         }
30 
31         // Merge sorted halves (now in src) into dest
32         for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
33             if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
34                 dest[i] = src[p++];
35             else
36                 dest[i] = src[q++];
37         }
38     }

第10行,根據Comparator接口實現類的compare方法的返回結果決定是否要swap(交換)。

這就是策略模式,我們可以給Collections的sort方法傳入不同的Comparator的實現類作為不同的比較策略。不同的比較策略,對同一個集合,可能會產生不同的排序結果。

策略模式優缺點

優點

1、避免了多重條件if...else if...else語句,多重條件語句並不容易維護

2、策略模式提供了管理相關算法簇的辦法,恰當使用繼承可以把公共代碼移到父類,從而避免了代碼重復

缺點

1、客戶端必須知道所有的策略類,並自行決定使用 哪一個策略,這意味着客戶端必須理解這些算法的區別,以便選擇恰當的算法

2、如果備選策略很多,對象的數據會很多

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM