前言
本人对于设计模式的学习,仅供参考!
一、Strategy策略模式
策略模式就是通过分别封装行为接口,实现算法族,超类中放行为接口对象在子类里面设定具体行为对象。简单来说,就是将算法与业务隔离开来,方便我们根据实际情况做出调整的模式。
策略模式使得算法可以在不受客户端影响的情况下发生变化,相当于可插入式的算法,可以使得在保持接口不变的情况下使具体算法可以互换
二、策略模式原则
其原则为:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为变化独立于算法的使用者。
其用意为:针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得他们可以相互替换。
三、使用场景
策略模式最经典的使用场景莫过于利用Comparator实现排序。
以下为Comparator接口的内容(只保留了一个抽象方法,其他方法为default)
public interface MyComparator<T> {
int compare(T o1,T o2);
}
1.先做比较练习
如果要按长度比较字符串,可以定义一个实现Comparator<String>的类。
在这里当返回值为1时代表o1字符串长度大于o2字符串长度,当返回值为-1时则代表o2字符串长度大于o1字符串长度,当返回值为0则代表他们字符串长度相等。
public class LengthComparator implements MyComparator<String> {
@Override
public int compare(String o1, String o2) {
if(o1.length()>o2.length()) return 1;
else if (o1.length()>o2.length()) return -1;
return 0;
}
}
2.为一组对象排序
现有一个Person类如下:
public class Person {
//名称
private String name;
//身高 单位cm
private int height;
//体重 单位kg
private int weight;
public Person(String name, int height, int weight) {
this.name = name;
this.height = height;
this.weight = weight;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", height=" + height +
", weight=" + weight +
'}';
}
}
现在对一个随机Person数组进行排序,基于Person类的信息我们可选择根据身高进行排序,或者根据体重进行排序,甚至可以按名称字符长度进行排序(不推荐)。
首先实现排序方法,这里选择的是“选择排序”的方法。
排序时我们选择使用一个比较器来判定两个对象的大小,比较器的接口Comparator。
比较器的实现
第一种:按身高比较
public class HeightComparator implements MyComparator<Person> {
@Override
public int compare(Person o1, Person o2) {
//选择身高进行比较
//大于则返回1
if (o1.getHeight() > o2.getHeight()) return 1;
//小于则返回-1
else if (o1.getHeight() < o2.getHeight()) return -1;
//相等则返回0
return 0;
}
}
第二种:按体重比较
public class WeightComparator implements MyComparator<Person> {
@Override
public int compare(Person o1, Person o2) {
//选择体重进行比较
//大于则返回1
if (o1.getWeight() > o2.getWeight()) return 1;
//小于则返回-1
else if (o1.getWeight() < o2.getWeight()) return -1;
//相等则返回0
return 0;
}
}
排序方法的实现
返回值为1时代表o1大于o2,当返回值为-1时则代表o1小于o2,当返回值为0则代表它们相等。
public class Sort<T> {
public void sort(T[] arr,MyComparator<T> comparator){
for (int i = 0; i < arr.length; 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);
}
}
public void swap(T[] arr,int i,int j){
T temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
当我们想按体重排序时只需要更换sort方法中的比较器参数,而不需要改动其他的代码,这种方式非常方便扩展维护。当需要按名称字符串长度排序时,只需要实现按名称长度排序的比较器而不需要修改原来的代码。
测试类中成功进行排序
public class Test {
public static void main(String[] args) {
Person[] people={new Person("张二",170,70),
new Person("李三三",175,55),
new Person("王五五五",178,80)};
Sort<Person> personSort=new Sort<>();
//按照身高排序
personSort.sort(people,new HeightComparator());
//按照体重排序
personSort.sort(people,new WeightComparator());
System.out.println(Arrays.toString(people));
}
}
3.使用Lambda表达式的方式
使用lambda表达式的形式可以使代码更加简洁,更有可读性。
//lambda表达式形式按照身高排序
personSort.sort(people,(o1,o2)->{
if (o1.getHeight()>o2.getHeight()) return 1;
else if (o1.getHeight()<o2.getHeight()) return -1;
return 0;
});