[design pattern](1) Strategy

引言

最近,在学习设计模式相关的知识。本博客主要想讲一讲策略模式,这也是我学习的第一个模式。写下这篇博客,主要想记录下个人的一点理解,也是想通过写博客的方式来加深对与Strategy的一点理解。以下的内容如果有什么说的不对的地方,还请各位大神指正。

思考题

首先我们来思考下面的一个问题:

问题:写出冒泡排序和快速排序算法,并且根据传参不同,使用不同的排序算法排序。

首先,来看没有使用设计模式的代码是什么样子:

SortAlgorithm.java:
import java.util.Random;
import java.util.Arrays;

public class SortAlgorithm {
    private static int index = 10000;
    private static int randomMax = 50000;
    private static Integer[] oldOrder = new Integer[index];
    private static Random random = new Random();
    static {
        for(int i = 0; i < index; i++) {
            oldOrder[i] = random.nextInt(randomMax);
        }
    }
    
    //通过设置算法名称来决定用什么算法
    private String algorithmName;
    
    public static void main(String... args) {
        SortAlgorithm sortAlgorithm = new SortAlgorithm();
        Integer[] oldOrder1 = Arrays.copyOf(oldOrder, index);
        Integer[] oldOrder2 = Arrays.copyOf(oldOrder, index);
        
        sortAlgorithm.setAlgorithmName("bubble");
        //System.out.println(String.format("BubbleSort sort before order:%s", Arrays.asList(oldOrder1).toString()));
        long startTime = System.currentTimeMillis();
        Integer[] newOrder1 = sortAlgorithm.executeAlgorithm(oldOrder1);
        System.out.println(String.format("BubbleSort take time:%s", System.currentTimeMillis() - startTime));
        //System.out.println(String.format("BubbleSort sort after order:%s", Arrays.asList(newOrder1).toString()));
        
        sortAlgorithm.setAlgorithmName("quick");
        //System.out.println(String.format("QuickSort sort before order:%s", Arrays.asList(oldOrder2).toString()));
        startTime = System.currentTimeMillis();
        Integer[] newOrder2 = sortAlgorithm.executeAlgorithm(oldOrder2);
        System.out.println(String.format("QuickSort take time:%s", System.currentTimeMillis() - startTime));
        //System.out.println(String.format("QuickSort sort after order:%s", Arrays.asList(newOrder2).toString()));
    }
    
    public Integer[] executeAlgorithm(Integer[] oldOrder) {
        if("bubble".equals(algorithmName)){
            return sortBubble(oldOrder);
        }else if("quick".equals(algorithmName)) {
            return sortQuick(oldOrder);
        }
        return null;
    }
    
    public void setAlgorithmName(String algorithmName) {
        this.algorithmName = algorithmName;
    }
    
    private Integer[] sortBubble(Integer[] oldOrder) {
        for(int i = 1; i < oldOrder.length; i++) {
            for(int j = 0; j < oldOrder.length - i; j++) {
                if(oldOrder[j] > oldOrder[j + 1]) {
                    Integer temp = oldOrder[j];
                    oldOrder[j] = oldOrder[j + 1];
                    oldOrder[j + 1] = temp;
                }
            }
        }
        return oldOrder;
    }
    
    private Integer[] sortQuick(Integer[] oldOrder) {
        partSort(oldOrder, 0, oldOrder.length - 1);
        return oldOrder;
    }
    
    private void partSort(Integer[] oldOrder, int start, int end) {
        if(start < end) {
            int middle = swaps(oldOrder, start, end);
            partSort(oldOrder, start, middle);
            partSort(oldOrder, middle + 1, end);
        }
    }
    
    private int swaps(Integer[] oldOrder, int start, int end) {
        Integer temp = oldOrder[start];
        for(;start < end;) {
            for(;start < end && temp <= oldOrder[end]; end--);
            if(start < end) {
                oldOrder[start] = oldOrder[end];
                start++;
            }
            for(;start < end && temp > oldOrder[start]; start++);
            if(start < end) {
                oldOrder[end] = oldOrder[start];
                end--;
            }
        }
        oldOrder[start] = temp;
        return start;
    }
}

print:

BubbleSort take time:717
QuickSort take time:14

上面是我的实现,所有的代码都集中在SortAlgorithm一个class里面。那么试想一下这时候如果我们想再增加一个选择排序,那么我们需要修改SortAlgorithm类,这样我们就违背了 开闭原则 。因此我们要想办法把修改变为增加。那么怎么样才能将修改变为增加呢?通过使用 strategy 可以做到。

介绍strategy

  • 定义: 定义一系列的算法,将每一个算法封装起来,并且让这些封装的算法之间可以相互替换。该模式可以使算法独立于使用它们的客户而变化。 
  • 类图:

 

通过上面的类图我们可以总结出一下几点:

  1. 具体算法类 ConcreteStrategyA 和 ConcreteStrategyA 都继承了 Strategy 接口,并且都实现了 algorithm 方法。通过实现接口我们可以很好的实践 开闭原则 ,我们也可以很好的实现扩展
  2. 类 Client 中有一个 Strategy 变量,通过设置这个变量我们可以很容易的转换我们的算法
  • 实现步骤:
  1. 首先定义一个接口
  2. 让所有的算法都实现这个接口
  3. 让客户端持有这个接口

重构思考题

 那么通过对Strategy的学习,我们来重构下我们上面的问题:

首先,我们定义一个接口:

Sort.java:

public interface Sort {
    Integer[] sort(Integer[] oldOrder);
}

然后,我们定义一系列的算法实现上面定义的接口:

BubbleSort.java:

public class BubbleSort implements Sort {
    @Override
    public Integer[] sort(Integer[] oldOrder) {
        for(int i = 1; i < oldOrder.length; i++) {
            for(int j = 0; j < oldOrder.length - i; j++) {
                if(oldOrder[j] > oldOrder[j + 1]) {
                    Integer temp = oldOrder[j];
                    oldOrder[j] = oldOrder[j + 1];
                    oldOrder[j + 1] = temp;
                }
            }
        }
        return oldOrder;
    }
}

QuickSort.java:

public class QuickSort implements Sort {
    @Override
    public Integer[] sort(Integer[] oldOrder) {
        partSort(oldOrder, 0, oldOrder.length - 1);
        return oldOrder;
    }
    
    private void partSort(Integer[] oldOrder, int start, int end) {
        if(start < end) {
            int middle = swaps(oldOrder, start, end);
            partSort(oldOrder, start, middle);
            partSort(oldOrder, middle + 1, end);
        }
    }
    
    private int swaps(Integer[] oldOrder, int start, int end) {
        Integer temp = oldOrder[start];
        for(;start < end;) {
            for(;start < end && temp <= oldOrder[end]; end--);
            if(start < end) {
                oldOrder[start] = oldOrder[end];
                start++;
            }
            for(;start < end && temp > oldOrder[start]; start++);
            if(start < end) {
                oldOrder[end] = oldOrder[start];
                end--;
            }
        }
        oldOrder[start] = temp;
        return start;
    }
}

最后,我们实现一个算法调用类:

SortAlgorithm.java:

public class SortAlgorithm {
    private Sort sort;
    
    public void setSort(Sort sort) {
        this.sort = sort;
    }
    
    public Integer[] executeAlgorithm(Integer[] oldOrder) {
        return sort.sort(oldOrder);
    }
}

测试用例:

Client.java:

import java.util.Random;
import java.util.Arrays;

public class Client {
    private static int index = 10;
    private static int randomMax = 100;
    private static Integer[] oldOrder = new Integer[index];
    private static Random random = new Random();
    static {
        for(int i = 0; i < index; i++) {
            oldOrder[i] = random.nextInt(randomMax);
        }
    }
    
    public static void main(String... args) {
        SortAlgorithm sortAlgorithm = new SortAlgorithm();
        Integer[] oldOrder1 = Arrays.copyOf(oldOrder, index);
        Integer[] oldOrder2 = Arrays.copyOf(oldOrder, index);
        
        sortAlgorithm.setSort(new BubbleSort());
        System.out.println(String.format("BubbleSort sort before order:%s", Arrays.asList(oldOrder1).toString()));
        long startTime = System.currentTimeMillis();
        Integer[] newOrder1 = sortAlgorithm.executeAlgorithm(oldOrder1);
        System.out.println(String.format("BubbleSort take time:%s", System.currentTimeMillis() - startTime));
        System.out.println(String.format("BubbleSort sort after order:%s", Arrays.asList(newOrder1).toString()));
        
        sortAlgorithm.setSort(new QuickSort());
        System.out.println(String.format("QuickSort sort before order:%s", Arrays.asList(oldOrder2).toString()));
        startTime = System.currentTimeMillis();
        Integer[] newOrder2 = sortAlgorithm.executeAlgorithm(oldOrder2);
        System.out.println(String.format("QuickSort take time:%s", System.currentTimeMillis() - startTime));
        System.out.println(String.format("QuickSort sort after order:%s", Arrays.asList(newOrder2).toString()));
    }
    
    private static int[] copyOldOrder(int[] oldOrder) {
        int[] result = new int[index];
        for(int i = 0; i < index; i++) {
            result[i] = oldOrder[i];
        }
        return result;
    }
}

上面的代码使用了策略模式,通过使用这个模式我们可以很容易的扩展,现在只要我们实现 Sort 接口就可以扩展我们的排序算法。

原文地址:https://www.cnblogs.com/cafebabe-yun/p/8987956.html