通过策略模式认识comparable接口与comparator接口

  comparable接口只是一个引子,引出策略模式中的接口comparator接口

  comparable接口的演变思想还是有价值去研究的

一.comparable接口演变

演变一:

  这一版本中运用选择排序实现了一个int类型最基本的排序功能

 

 1 public class Sorter {
 2 
 3     public static void sort(int[] arr) {
 4         for (int i=0; i<arr.length - 1; i++){
 5             int minPoint = i;
 6 
 7             for(int j=i+1; j<arr.length; j++){
 8                 minPoint = arr[j] < arr[minPoint] ? j : minPoint;
 9             }
10 
11             swap(arr, i, minPoint);
12         }
13     }
14 
15     static void swap(int[] arr, int i , int j){
16         int temp = arr[i];
17         arr[i] = arr[j];
18         arr[j] = temp;
19     }
20 }
1 public class Main {
2     public static void main(String[] args) {
3         int[] a = {9,2,3,5,7,1,4};
4         Sorter sorter = new Sorter();
5         sorter.sort(a);
6         System.out.println(Arrays.toString(a));
7     }
8 }

  问一:如果要对float类型的数字进行排序怎么办?对double类型、byte类型呢?

    答:只需要在Sorter类中重写sort方法就能实现

  问二:如果要对一些引用数据类型进行排序呢?

    答:这一版本肯定是不行的

演变二:

  接问题二进而有了第二个版本,针对引用数据类型进行排序,我们这里举例Cat

  那么怎么比较猫的大小呢?这里就需要我们编写方法规定好比较规则了(CompareTo方法)

 1 public class Cat {
 2     int weight,height;
 3 
 4     public Cat(int weight,int height){
 5         this.weight = weight;
 6         this.height = height;
 7     }
 8 
 9     public int compareTo(Cat cat){
10         if (this.weight < cat.weight) return -1;
11         else if(this.weight > cat.weight) return 1;
12         else return 0;
13     }
14 
15     @Override
16     public String toString() {
17         return "Cat{" +
18                 "weight=" + weight +
19                 ", height=" + height +
20                 '}';
21     }
22 }
 1 public class Sorter {
 2 
 3     public static void sort(Cat[] arr) {
 4         for (int i=0; i<arr.length - 1; i++){
 5             int minPoint = i;
 6 
 7             for(int j=i+1; j<arr.length; j++){
 8                 minPoint = arr[j].compareTo( arr[minPoint] ) == -1 ? j : minPoint;
 9             }
10             swap(arr, i, minPoint);
11         }
12     }
13 
14     static void swap(Cat[] arr, int i , int j){
15         Cat temp = arr[i];
16         arr[i] = arr[j];
17         arr[j] = temp;
18     }
19 }
1 public class Main {
2     public static void main(String[] args) {
3         Cat[] cat = {new Cat(3,3), new Cat(5,5), new Cat(1,1)};
4         Sorter sorter = new Sorter();
5         sorter.sort(cat);
6         System.out.println(Arrays.toString(cat));
7     }
8 }

  问三:这个版本中我们对Cat类进行了排序,那么如果我要对Dog类、Egg类进行排序怎么办?

    答:我们可以将Sorter类中传入sort方法的参数类型设置为Object类型

  问四:解决了上面问三,但是Object类中并没有compareTo方法怎么办?

    答:可以新建一个接口,里面定义compareTo方法,所有参与比较的类都要实现该接口

演变三:

  解决问三、问四问题

1 public interface Comparable {
2     //为了实现多个类共用此方法,这里将传入参数设置为Object类型
3     public int compareTo(Object o);
4 }
 1 public class Sorter {
 2     //为了实现共用,而将传入参数设置为Comparable
 3     public static void sort(Comparable[] arr) {
 4         for (int i=0; i<arr.length - 1; i++){
 5             int minPoint = i;
 6 
 7             for(int j=i+1; j<arr.length; j++){
 8                 minPoint = arr[j].compareTo( arr[minPoint] ) == -1 ? j : minPoint;
 9             }
10             swap(arr, i, minPoint);
11         }
12     }
13 
14     static void swap(Comparable[] arr, int i , int j){
15         Comparable temp = arr[i];
16         arr[i] = arr[j];
17         arr[j] = temp;
18     }
19 }
 1 public class Dog implements Comparable {
 2 
 3     int food;
 4 
 5     public Dog(int food){
 6         this.food = food;
 7     }
 8 
 9     //这里传入参数为Object类型
10     @Override
11     public int compareTo(Object o) {
12         //这里要使用Dog类型进行转换时,需要将Object类型的参数转换为Dog类型
13         Dog dog = (Dog)o;
14         if (this.food<dog.food) return -1;
15         else if (this.food<dog.food) return 1;
16         else return 0;
17     }
18 
19     @Override
20     public String toString() {
21         return "Dog{" +
22                 "food=" + food +
23                 '}';
24     }
25 }
 1 public class Cat implements Comparable{
 2     int weight,height;
 3 
 4     public Cat(int weight,int height){
 5         this.weight = weight;
 6         this.height = height;
 7     }
 8 
 9     //这里传入参数为Object类型
10     public int compareTo(Object o){
11         //这里要使用Cat类型进行转换时,需要将Object类型的参数转换为Cat类型
12         Cat cat = (Cat)o;
13         if (this.weight < cat.weight) return -1;
14         else if(this.weight > cat.weight) return 1;
15         else return 0;
16     }
17 
18     @Override
19     public String toString() {
20         return "Cat{" +
21                 "weight=" + weight +
22                 ", height=" + height +
23                 '}';
24     }
25 }
1 public class Main {
2     public static void main(String[] args) {
3         Dog[] dogs = {new Dog(3), new Dog(5), new Dog(1)};
4         Sorter sorter = new Sorter();
5         sorter.sort(dogs);
6         System.out.println(Arrays.toString(dogs));
7     }
8 }

  问五:如果比较对象与被比较对象类型不相同,那么传入参数进行强制转换时就会报错

    答:利用java中泛型在演变三基础上进行修改

演变四:

  在上一个版本基础上利用泛型进行代码修改

  仅展示部分修改后代码,未修改的部分参照演变三中代码

1 //加上泛型,更加灵活
2 public interface Comparable<T> {
3     //不必设置为Object类型
4     public int compareTo(T o);
5 }
 1 //实现接口时传入泛型
 2 public class Dog implements Comparable<Dog> {
 3 
 4     int food;
 5 
 6     public Dog(int food){
 7         this.food = food;
 8     }
 9 
10     //实现接口中方法,将传入参数确定比较类型
11     @Override
12     public int compareTo(Dog dog) {
13         //增加泛型后这里减少了强制转换带来的隐患
14         if (this.food<dog.food) return -1;
15         else if (this.food<dog.food) return 1;
16         else return 0;
17     }
18 
19     @Override
20     public String toString() {
21         return "Dog{" +
22                 "food=" + food +
23                 '}';
24     }
25 }

演变五:

  最完美的结果就是实现java中自带的comparable接口

二.comparator接口

  接着上面comparable接口,在猫这个实体类在comparable接口中的比较策略是通过比较体重来进行判断的。但是,实际生活中比较猫可以通过很多方面,如体重、身高、身长等。那么怎样实现猫比较大小的策略可以灵活指定呢?

  这里在解决上述问题时将原本的一个泛型变为两个泛型,第一个泛型为比较的数组,第二个泛型为打比较的策略。如果需要添加新的比较策略,只需在新建类中定义具体比较策略并实现相应接口,在需要调用时利用多态new出不同实现类即可实现不同方式的比较策略

1 public interface Comparator<T> {
2     //定义两个泛型,第一个为比较数组,第二个为比较策略
3     public int compare(T o1,T o2);
4 }
 1 /**
 2  * 狗的比较器
 3  * 具体实现类,定义狗的具体比较策略
 4  */
 5 public class DogComparator implements Comparator<Dog> {
 6     @Override
 7     public int compare(Dog o1, Dog o2) {
 8         if (o1.food<o2.food) return -1;
 9         else if (o1.food>o2.food) return 1;
10         else return 0;
11     }
12 }
 1 public class Sorter<T> {
 2     /**
 3      * 比较方法在调用时需要传入两个参数
 4      * 第一个参数为需要参与比较的数组,数组中存放n个狗的对象
 5      * 第二个参数为狗进行比较时的具体比较策略,这个根据具体需求利用多态new出来即可
 6      */
 7     public void sort(T[] arr,Comparator<T> comparator) {
 8         for (int i=0; i<arr.length - 1; i++){
 9 
10             int minPoint = i;
11 
12             for(int j=i+1; j<arr.length; j++){
13                 minPoint = comparator.compare(arr[j], arr[minPoint] ) == -1 ? j : minPoint;
14             }
15             swap(arr, i, minPoint);
16         }
17     }
18 
19     void swap(T[] arr, int i , int j){
20         T temp = arr[i];
21         arr[i] = arr[j];
22         arr[j] = temp;
23     }
24 }
 1 public class Dog {
 2 
 3     int food;
 4 
 5     public Dog(int food){
 6         this.food = food;
 7     }
 8 
 9     @Override
10     public String toString() {
11         return "Dog{" +
12                 "food=" + food +
13                 '}';
14     }
15 }
1 public class Main {
2     public static void main(String[] args) {
3         Dog[] dogs = {new Dog(3), new Dog(5), new Dog(1)};
4         Sorter sorter = new Sorter();
5         sorter.sort(dogs,new DogComparator());
6         System.out.println(Arrays.toString(dogs));
7     }
8 }

 

上一篇:Java中Comparable和Comparator的区别


下一篇:Map.Entry 接口