策略模式是什么?
策略模式定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化。 以上定义来自设计模式之美
是不是很抽象,下面我们就用模拟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 语句
- 策略模式符合开闭原则
- 缺点
- 必须知道所有的策略,并且自行决定使用哪一个策略类。
- 代码中会产生非常多策略类,增加维护难度。