设计模式之策略模式

1. 策略模式的作用

  在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。

2. 为什么要使用策略模式?

  我们想象一下最常见的场景:排序。排序无非两种选择,升序或降序。如果我们要封装一个类要自由的切换两种排序要怎么做呢?

  最常见的做法是这样的:

   

public class Demo {
    public void sort(boolean asc) { 
        if (asc) {   //判断是否要升序
            //实现升序的算法
        } else {
            //实现降序的算法
        }
    }
}

  

  我们可以发现这要的代码极不美观,而且这还是只有两种情况的时候,加入有N中情况那岂不是要写很多的判断。甚至可能大多数时候我们并不能提前想好所有的类型,如果临时要加入新的算法只能再次修改原来的代码。维护很困难。这时候我们就可以使用策略模式来实现。

3. 怎么使用策略模式?

  以上述排序为例,在java中我们需要实现自己的比较器。

  

public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
    }

  如此,当我们在需要定义新的排序规则(因为排序的对象可能是多种多样的),当我们需要一个新的规则时,我们不需要去修改Collections.sort()方法的内容,而是实现一个自己的比较器,这样就可以实现新的排序。

4. 分析一下策略模式是怎么构成的?

  我们同样以上述排序为例:

  (1)策略接口

@FunctionalInterface
public interface Comparator<T> {  这是策略接口

int compare(T o1, T o2); 这是实现不同策略的接口函数


  (2)不同的实现

class MyComparator4Integer implements Comparator{   //为了比较Integer类型而实现的类

    @Override
    public int compare(Object o1, Object o2) {
        return 0;
    }
}


class MyComparator4String implements Comparator{ //为了比较String类型而实现的类

@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
 

  (3)调用者中(其中一个

private static <T> void binarySort(T[] a, int lo, int hi, int start,
                                       Comparator<? super T> c) {
        assert lo <= start && start <= hi;
        if (start == lo)
            start++;
        for ( ; start < hi; start++) {
            T pivot = a[start];

            // Set left (and right) to the index where a[start] (pivot) belongs
            int left = lo;
            int right = start;
            assert left <= right;
            /*
             * Invariants:
             *   pivot >= all in [lo, left).
             *   pivot <  all in [right, start).
             */
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (c.compare(pivot, a[mid]) < 0)   //在调用者中会调用策略函数,当传入的比较器不同时,比较的规则也会随之改变
                    right = mid;
                else
                    left = mid + 1;
            }
            assert left == right;

            /*
             * The invariants still hold: pivot >= all in [lo, left) and
             * pivot < all in [left, start), so pivot belongs at left.  Note
             * that if there are elements equal to pivot, left points to the
             * first slot after them -- that's why this sort is stable.
             * Slide elements over to make room for pivot.
             */
            int n = start - left;  // The number of elements to move
            // Switch is just an optimization for arraycopy in default case
            switch (n) {
                case 2:  a[left + 2] = a[left + 1];
                case 1:  a[left + 1] = a[left];
                         break;
                default: System.arraycopy(a, left, a, left + 1, n);
            }
            a[left] = pivot;
        }
    }

  

  

原文地址:https://www.cnblogs.com/liwangcai/p/11872874.html