【Java设计模式】之以Comparator比较器为例学习策略模式

对整型数组排序

假设现在我们要写一个类,其 sort() 方法可以接收一个整型数组,然后对该整型数组进行排序。那么排序部分的代码就差不多应该这样写:

public class Sort {
    public static void sort(int[] arr) {
        int i, j = 0;
        int temp;
        for (i = 0; i < arr.length; i++) {
            for (j = 1; j < arr.length - i; j++) {
                //如果前面的元素大于后面的,则交换位置
                if (arr[j - 1] > arr[j]) {
                    temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j-1] = temp;
                }
            }
        }
    }
}
image-20201216104034412

从截图可以看到现在完全满足了整型排序的需求。

对自定义类数组排序

假设现在我们需要变更一下需求,要实现对 Person 类数组按身高大小进行排序,那么现在的排序方法显然不能满足。

public class Person {
    //身高
    private int height;
    //体重
    private int weight;
    
    //其他方法省略
}

对于这个需求,我们可能会想到让每个类都继承Comparable 接口并实现其 compareTo() 方法,定义其比较规则。那么代码就要更改为如下所示:

public class Person implements Comparable<Person>{
    //身高
    private int height;
    //体重
    private int weight;
	//其他方法省略
	
    @Override
    public int compareTo(Person o) {
        if (o.height > height) {
            return -1;
        } else if (o.height < height) {
            return 1;
        } else {
            return 0;
        }
    }
}
public class Sort{
    public void sort(Comparable[] arr) {
        int i, j = 0;
        Comparable temp;
        for (i = 0; i < arr.length; i++) {
            for (j = 1; j < arr.length - i; j++) {
                //如果前面的元素大于后面的,则交换位置
                if (arr[j - 1].compareTo(arr[j]) > 0) {
                    temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                }
            }
        }
    }
}
image-20201216125820378

到这里,我们只要为我们想要排序的类添加比较规则,那么就都能实现排序。例如现在对猫排序:

public class Cat implements Comparable<Cat> {
    //体重
    private int weight;
    //身体长度
    private int length;
	//其他代码省略
    @Override
    public int compareTo(Cat o) {
        if (o.length < length) {
            return 1;
        } else if (o.length > length) {
            return -1;
        } else {
            return 0;
        } 
    }
}
image-20201216130606917

现在这中方法看起来已经可以实现对不同类型对象进行排序了,但灵活性还是不够高,还是需要进行优化。

假设现在我们对 Person 类排序时重新定义规则,按照其 weight 属性的大小进行排序,那么现有的这种继承 Comparable 接口的方式就不能很好满足需求,不得不对 Person 类的 compareTo() 进行修改。

在设计模式中,一个非常重要的原则是 开闭原则,即对扩展开放,对修改关闭。很显然上述通过修改类中方法就不满足开闭原则。所以有没有更好的方式做到对 Person 类进行排序呢?

答案是肯定的,那就是把每个类的比较规则从类中分离出来成为一个单独的类,像下面这样(以Person类为例):

//Person类的比较器
public class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        if (o1.getWeight() < o2.getWeight()) {
            return -1;
        } else if (o1.getWeight() > o2.getWeight()) {
            return 1;
        } else {
            return 0;
        }
    }
}

Person类:在Person类中不用再实现compareTo()方法

public class Person{
    //身高
    private int height;
    //体重
    private int weight;
    
    //省略其他代码
}
image-20201216132340940

此时如果再对该Person类中添加一些其他属性,按照不同的规则进行排序,例如按照大长腿进行排序,也只需要添加相应的属性和比较器即可,无需修改已有代码,非常复合开闭原则。

上述需求的解决方式,其实就运用到了设计模式中的 策略模式

策略模式

定义

定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。
策略模式让算法可以独立于使用它的客户而变化。

适用场景

策略模式用于算法的自由切换和扩展,它对应于解决一个问题的一个算法族,
允许用户从该算法族中任选一个算法来解决某一问题,同时可以方便地更换
算法或者增加新的算法。只要涉及到算法的封装,服用和切换都可以考虑使用策略模式。

优点

  • 提供了对开闭原则的完美支持,在不修改原有代码基础上即可灵活增加新的算法或者行为
  • 提供了管理相关的算法族的办法,可以通过使用继承把不同策略中的公共代码抽象出来
  • 提供了一种可以替换继承关系的办法。策略与环境分离开来,可以避免由于继承关系带来的复杂问题
  • 使用策略模式可以避免多重条件选择语句
  • 提供了一种算法复用机制,由于算法是单独地提取出来进行封装,因此不同的环境类可以方便地进行复用

缺点

  • 客户端必须知道所有的策略类,并需要自行决定使用哪一种策略。因此该模式只适用于客户端知道所有策略的情况
  • 策略模式会导致系统产生过多的具体策略类
  • 无法同时在客户端使用多个策略类
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值