策略模式是什么?
策略模式定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化。 以上定义来自设计模式之美
是不是很抽象,下面我们就用模拟Comparator接口为大家讲解策略模式,首先我定义一个Cat类,里面有weight,height,age 属性
public class Cat { int weight, height,age; public Cat(int weight, int height,int age) { this.weight = weight; this.height = height; this.age = age; } @Override public int compareTo(Cat c) { if(this.weight < c.weight) { return -1; } else if(this.weight > c.weight) { return 1; } else { return 0; } } @Override public String toString() { return "Cat{" + "weight=" + weight + ", height=" + height + ", age=" + age + '}'; } } 复制代码
现在我们要实现Cat类数组的排序,按weight属性升序,我们定义一个Sorter类,Cat类中定义compareTo方法,方法是按Cat类中的weight属性比较,我们通过选择排序实现Cat数组的排序
public class Sorter { public void sort(Cat[] arr) { //选择排序 for(int i=0; i<arr.length - 1; i++) { int minPos = i; for(int j=i+1; j<arr.length; j++) { minPos = arr[j].compareTo(arr[minPos])==-1 ? j : minPos; } swap(arr, i, minPos); } } void swap(Cat[] arr, int i, int j) { Cat temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void main(String[] args) { Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)}; Sorter sorter = new Sorter(); sorter.sort(a); System.out.println(Arrays.toString(a)); } } 复制代码
假如现在我们要实现Cat类heigt属性或age属性排序,我们是不是每次都要修改compareTo方法,在设计模式中,有个对修改关闭,对扩展开放的开闭原则,我们每次都去修改compareTo方法违背了设计模式的思想,我们怎么进行扩展,我们定义Comparator接口,我们要实现那个属性的排序,就定义哪个属性的比较器
public interface Comparator<T> { int compare(T o1, T o2); } 复制代码
height升序属性的比较器
public class CatHeightComparator implements Comparator<Cat> { @Override public int compare(Cat o1, Cat o2) { if(o1.height > o2.height) { return 1; } else if (o1.height < o2.height) { return -1; } else { return 0; } } } 复制代码
public void sort(T[] arr, Comparator<T> comparator) { for(int i=0; i<arr.length - 1; i++) { int minPos = i; for(int j=i+1; j<arr.length; j++) { minPos = comparator.compare(arr[j],arr[minPos])==-1 ? j : minPos; } swap(arr, i, minPos); } } void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void main(String[] args) { Cat[] a = {new Cat(3, 3, 3), new Cat(5, 5, 5), new Cat(1, 1, 1)}; Sorter<Cat> sorter = new Sorter<>(); sorter.sort(a,new CatHeightComparator()); System.out.println(Arrays.toString(a)); } 复制代码
以此类推,我们要实现age属性的排序,我义Cat类age的比较器,要实现weight属性的排序,就实现Cat类weight比较器,以上就是Comparator接口实现策略模式的过程,我们可以提前的把这些比较器定义成枚举类,在程序初始化的时候将每个比较器放入常量map当中,想要那种比较器就从map中取,避免if...else...判断,增加一个策略,就在初始化了添加一个
public enum ComparatorEnum { AGE("age","age排序"), WEIGHT("weight","weight排序"), HEIGHT("height","height排序"); private String code; private String desc; ComparatorEnum(String code, String desc) { this.code = code; this.desc = desc; } public String getCode() { return code; } public String getDesc() { return desc; } } 复制代码
private static final Map<String, Comparator> comparatorMap= new HashMap<>(); static { shareStrategies.put("height", new CatHeightComparator()); ... ... } 复制代码
策略模式优缺点
- 优点
- 算法策略可以自由切换
- 避免使用多重条件转移语句,如if...else...语句、switch 语句
- 策略模式符合开闭原则
- 缺点
- 必须知道所有的策略,并且自行决定使用哪一个策略类。
- 代码中会产生非常多策略类,增加维护难度。