zoukankan      html  css  js  c++  java
  • 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、如果备选策略很多,对象的数据会很多

  • 相关阅读:
    jmeter(46) redis
    jmeter(45) tcp/ip协议
    Codeforces Round #538 (Div. 2)D(区间DP,思维)
    Codeforces Global Round 1D(DP,思维)
    Educational Codeforces Round 57D(DP,思维)
    UPC11073(DP,思维)
    Yahoo Progamming Contest 2019D(DP,思维)
    Atcoder Beginner Contest 118D(DP,完全背包,贪心)
    Xuzhou Winter Camp 1C(模拟)
    Educational Codeforces Round 57 (Rated for Div. 2)D(动态规划)
  • 原文地址:https://www.cnblogs.com/sunl123/p/11105261.html
Copyright © 2011-2022 走看看