• 设计模式之策略模式


      针对Java语言,最主要的一个思想是面对对象设计(OOP)。在面向对象设计的开发过程中,需要用到各种设计模式,其中策略模式作为其中一个应用最为常见的模式之一,在生产过程中广泛应用。我们知道,在面向对象开发过程中,经常用到继承和多态,其与策略模式的基本思想是基本一致的。

           在实际开发过程中,经常遇到的一种业务场景是 对于某一种行为采取不同的处理方法。比如说,对用户进行分级,针对不同级别的用户,进行不同的处理方式;再比如,针对同一个问题,进行多种不同的处理方式,对于多种处理方式进行比较。策略模式应运而生,策略模式是处理算法不同变体的一种成熟模式,策略模式通过接口或抽象类封装算法的标识,即在接口中定义一个抽象方法,实现该接口的类将实现接口中的抽象方法。策略模式把针对一个算法标识的一系列具体算法分别封装在不同的类中,使得各个类给出的具体算法可以相互替换。如下,是策略模式的结构图。

    策略模式的角色

           在策略模式中,存在三种角色,分别是策略(Strategy)、具体策略(ConcreteStrategy)和封装类(Context)。

      1) 策略(Strategy):策略是一个接口,在这个接口中我们定义了很多的抽象方法。

      2) 具体策略(ConcreteStrategy):具体策略是策略接口的实现类,在这个实现类中,我们对于其抽象方法进行了重写,可以定义多个具体策略。即在具体策略中,我们实现对于同一种行为多种处理方式的定义,在具体策略中进行多种处理。

      3) 封装(Context):即上下文。上下文中,通常会定义一个策略接口作为类中的一个属性,并且定义一个方法,通过这个定义的方法来调用策略接口的抽象方法。通过调用不同的策略接口的实现类,从而实现对于同一种行为的不同的处理方式。

    策略模式的优缺点

      策略模式的优点如下:

      1) 多个具体策略可以自由切换,因为每一个具体策略都是实现了策略接口,因此,我们只要切换接口的实现类,即可实现具体策略的切换。

      2) 易于扩展,符合“开闭原则”。当增加或者减少新的具体策略时,只需要增加或者减少具体策略的定义即可,上下文中的内容不需要修改,只需要在调用上下文对象的主方法中更改调用即可。

      策略模式的缺点如下:

      1) 增加维护成本,除了维护策略以及多个具体策略实现类,还需要维护上下文对象等。

      2) 对于开发人员来说,除了需要策略模式中各个类的关系,还需要特别关注多个具体策略的业务逻辑,不符合迪米特法则(Law of Demeter)即最少知识原则。

    策略模式的具体实现

           如上所述,在策略模式的demo 中,定义了策略接口、多个具体策略实现类、上下文以及一个主程序。所选用的业务场景就是对于一个数组进行多种不同的排序方法。

      1) 策略:策略接口的名字是 SortStrategy,定义的抽象方法是 sortArray,即对于一个数组进行排序。具体代码如下。

    1 import java.util.List;
    2 
    3 /**
    4  * 策略
    5  */
    6 public interface SortStrategy {
    7     public abstract List<Integer> sortArray(Integer[] a);
    8 }

      2) 具体策略,具体策略是对策略接口的实现类,在本示例中,一共定义了三个具体策略实现类,分别对应冒泡排序、插入排序和快速排序等。具体代码如下。

       具体策略一:

    /**
     * 具体策略一: 冒泡排序
     */
    public class StrategyOne implements SortStrategy {
    
        @Override
        public List<Integer> sortArray(Integer[] a) {
    
            for (int i = 0; i < a.length; i++) {
                for (int j = 0; j < a.length - 1 - i; j++) {
                    if (a[j] > a[j + 1]) {
                        int temp = a[j + 1];
                        a[j + 1] = a[j];
                        a[j] = temp;
                    }
                }
            }
    
            System.out.println("调用了冒泡排序");
            return new ArrayList<>(Arrays.asList(a));
        }
    }

      具体策略二:

     1 /**
     2  * 具体策略二: 插入排序
     3  */
     4 public class StrategyTwo implements SortStrategy {
     5 
     6     @Override
     7     public List<Integer> sortArray(Integer[] a) {
     8 
     9         for (int i = 1; i < a.length; i++) {
    10             Integer temp = a[i];
    11             int j;
    12             for (j = i - 1; j >= 0; j--) {
    13                 if (a[j] > temp) {
    14                     a[j + 1] = a[j];
    15                 } else {
    16                     break;
    17                 }
    18             }
    19             a[j + 1] = temp;
    20         }
    21         System.out.println("调用了插入排序");
    22 
    23 
    24         return new ArrayList<>(Arrays.asList(a));
    25     }
    26 }

      具体策略三:

     1 /**
     2  * 具体策略三: 快速排序
     3  */
     4 public class StrategyThree implements SortStrategy {
     5 
     6     @Override
     7     public List<Integer> sortArray(Integer[] a) {
     8 
     9         if (a == null || a.length == 0) {
    10             return null;
    11         }
    12         quickSort(a, 0, a.length - 1);
    13         System.out.println("调用了快速排序");
    14 
    15         return new ArrayList<>(Arrays.asList(a));
    16     }
    17 
    18     private void quickSort(Integer[] a, int start, int end) {
    19         if (start >= end) {
    20             return;
    21         }
    22         int flag = partition(a, start, end);
    23         quickSort(a, start, flag - 1);
    24         quickSort(a, flag + 1, end);
    25     }
    26 
    27     private int partition(Integer[] a, int left, int right) {
    28         int target = left;
    29         int targetValue = a[left];
    30         while (left < right) {
    31             while (left < right && a[right] >= targetValue) {
    32                 right--;
    33             }
    34             while (left < right && a[left] <= targetValue) {
    35                 left++;
    36             }
    37             customSwap(a, left, right);
    38         }
    39         customSwap(a, target, left);
    40         return left;
    41     }
    42 
    43     private void customSwap(Integer[] a, int i, int j) {
    44         Integer temp = a[i];
    45         a[i] = a[j];
    46         a[j] = temp;
    47     }
    48 
    49 }

      3) 封装类即上下文对象:其中定义了策略的常量及一个调用策略抽象方法的实现类。具体代码如下。

     1 public class StrategyContext {
     2 
     3     private SortStrategy sortStrategy;
     4 
     5     public StrategyContext(SortStrategy sortStrategy) {
     6         this.sortStrategy = sortStrategy;
     7     }
     8 
     9     public void customSort(Integer[] a){
    10         sortStrategy.sortArray(a);
    11     }
    12 
    13     public StrategyContext() {
    14     }
    15 
    16     public void setSortStrategy(SortStrategy sortStrategy) {
    17         this.sortStrategy = sortStrategy;
    18     }
    19 }

      4) 主程序:在主程序中new了多个上下文对象,分别调用不同的具体策略,从而实现业务逻辑,具体代码如下。

    import java.util.Arrays;
    
    public class StrategyApplication {
    
        public static void main(String[] args) {
    
            Integer[] initArrayOne = {11,19,18,13,12,14};
            Integer[] initArrayTwo = {21,29,28,23,22,24};
            Integer[] initArrayThree = {31,39,38,33,32,34};
    
            StrategyContext strategyContextOne = new StrategyContext();
            strategyContextOne.setSortStrategy(new StrategyOne());
            strategyContextOne.customSort(initArrayOne);
            System.out.print("StrategyOne排序后: ");
            System.out.println(Arrays.toString(initArrayOne));
            System.out.println();
    
            StrategyContext strategyContextTwo = new StrategyContext();
            strategyContextTwo.setSortStrategy(new StrategyTwo());
            strategyContextTwo.customSort(initArrayTwo);
            System.out.print("StrategyTwo排序后: ");
            System.out.println(Arrays.toString(initArrayTwo));
            System.out.println();
    
            StrategyContext strategyContextThree = new StrategyContext();
            strategyContextThree.setSortStrategy(new StrategyThree());
            strategyContextThree.customSort(initArrayThree);
            System.out.print("StrategyThree排序后: ");
            System.out.println(Arrays.toString(initArrayThree));
            System.out.println();
        }
    }

      5) 运行接果如下。

       

      

  • 相关阅读:
    codevs1735 方程的解数(meet in the middle)
    cf280C. Game on Tree(期望线性性)
    使用ASP.NET上传多个文件到服务器
    Oracle DB 数据库维护
    poj 3237(树链剖分+线段树)
    undefined reference to 'pthread_create'
    ios开发-调用系统自带手势
    Mysql创建、删除用户、查询所有用户等教程,提升您的MYSQL安全度!
    Number Sequence_hdu_1005(规律)
    SCU 4313 把一棵树切成每段K个点 (n%k)剩下的点不管
  • 原文地址:https://www.cnblogs.com/Demrystv/p/11874449.html
Copyright © 2020-2023  润新知