美文网首页程序员
java设计模式-策略模式(包含Comparable接口和泛型的

java设计模式-策略模式(包含Comparable接口和泛型的

作者: methon | 来源:发表于2020-08-31 22:21 被阅读0次

    1.为什么需要Comparable接口

    举一个简单的例子,对int数组元素进行选择排序。程序如下:

    package com.methon.comparable;
    
    public class Sorter {
        public static void sort(int[] arr) {
            for (int i = 0; i < arr.length; i++) {
                int minPos = i;
                for (int j = i + 1; j < arr.length; j++) {
                    minPos = arr[j] < arr[minPos] ? j : minPos;
                }
                swap(arr, i, minPos);
            }
        }
    
        static void swap(int[] arr, int i, int j) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    
    
    package com.methon.comparable;
    
    import java.util.Arrays;
    
    public class TestA {
        public static void main(String[] args) {
            int a[]={3,4,2,1,5};
            Sorter sorter=new Sorter();
            sorter.sort(a);
            System.out.println(Arrays.toString(a));
        }
    }
    
    

    可以看到输出的结果递增有序。
    稍微复杂些,假设需要对对象进行排序呢?
    有一个Cat对象,如何根据成员变量weight进行排序呢?请看下面的代码。

    package com.methon.comparable;
    
    public class Cat {
        int weight;
        int height;
    
        public Cat(int weight, int height) {
            this.weight = weight;
            this.height = height;
        }
    
        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 +
                    '}';
        }
    }
    
    
    package com.methon.comparable;
    
    public class Sorter {
        public static void sort(Cat[] arr) {
            for (int i = 0; i < arr.length; 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);
            }
        }
    
        static void swap(Cat[] arr, int i, int j) {
            Cat temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    
    
    package com.methon.comparable;
    
    import java.util.Arrays;
    
    public class TestA {
        public static void main(String[] args) {
            Cat[] catArr={new Cat(3,5),new Cat(4,7),new Cat(1,3)};
            Sorter sorter=new Sorter();
            sorter.sort(catArr);
            System.out.println(Arrays.toString(catArr));
        }
    }
    
    

    可以看出,我们有一个Cat类,里面包含一个compareTo方法。小于为-1,大于为1.等于为0.
    我们对Sorter类进行了简单的修改,sort方法传入对象由int[]变成了Cat[].
    排序时候

     minPos = arr[j].compareTo(arr[minPos]) == -1 ? j : minPos;
    

    直接调用了Cat类里的compareTo方法比较大小。
    如果我们还有一个Dog类也需要排序呢?还需要在定义一个sort方法传入Dog[]吗?

    2.使用Comparable接口里的compareTo方法

    有人可能会说不用,直接将sort方法中的Cat[]传参改为Object[]。
    但是这样存在一个问题,Object类中没有compareTo方法。不能进行比较
    java中提供了Comparable接口。所有要排序的都可以重写Comparable接口中的compareTo方法。从而实现排序。代码如下:

    public class Sorter {
    
    
        public static void sort(Comparable[] arr) {
            for (int i = 0; i < arr.length; 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);
            }
        }
    
        static void swap(Comparable[] arr, int i, int j) {
            Comparable temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    
    
     @Override
        public int compareTo(Object o) {
            Cat c = (Cat) o;
            if (this.weight < c.weight) {
                return -1;
            } else if (this.weight > c.weight) {
                return 1;
            } else {
                return 0;
            }
        }
    
    

    我们注意到,Cat类中compareTo方法定义如下public int compareTo(Object o)。传入的参数是Object o,使用时候强制转换成Cat类型。
    那么有没有一种方法不用进行强制转换呢?

    3.使用泛型定义自己的Comparable接口

    自己定义的接口如下:

    public interface Comparable<T> {
        public int compareTo(T o);
    }
    
    
    image.png

    上面的Comparable传入T类型的数据,那么compareTo就使用T类型的参数。可以把T想象成Object。
    Cat类修改后的代码如下:

    public class Cat implements Comparable<Cat> {
        int weight;
        int height;
    
        public Cat(int weight, int height) {
            this.weight = weight;
            this.height = height;
        }
    
        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 +
                    '}';
        }
    
    }
    
    

    有两个需要注意的事项
    1.implements Comparable代码后要给泛型赋值<Cat>.如不写默认为Object。


    image.png

    2.Comparable传入什么类型的泛型,compareTo就必须传入相同类型的参数。否则会报错。


    image.png

    4.定义自己的Comparable(策略模式)

    根据java的设计原则,我们应该对修改关闭,对扩展开放。所以我们需要尽可能不对源代码进行修改。
    对于上面的Cat类,我们想按照weight进行排序,如果之后我们想根据height进行排序呢?
    所以我们定义自己的Comparable,使用泛型控制传入参数的类型。

    public interface Comparator<T> {
        int compare(T o1,T o2);
    }
    
    
    public class Sorter<T> {
    
    
        public  void sort(T[] arr,Comparator<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);
            }
        }
    
         void swap(T[] arr, int i, int j) {
            T temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    
    
    public class Cat {
        int weight;
        int height;
    
        public Cat(int weight, int height) {
            this.weight = weight;
            this.height = height;
        }
    
        @Override
        public String toString() {
            return "Cat{" +
                    "weight=" + weight +
                    ", height=" + height +
                    '}';
        }
    
    }
    
    
    public class CatComparator implements  Comparator<Cat>{
    
        @Override
        public int compare(Cat o1, Cat o2) {
            if(o1.weight<o2.weight){
                return -1;
            }else if(o1.weight>o2.weight){
                return 1;
            }else {
                return 0;
            }
        }
    }
    
    
    import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
    
    import java.util.Arrays;
    
    public class Main {
        public static void main(String[] args) {
            Cat[] cats={new Cat(3,3),new Cat(1,1),new Cat(5,5)};
            Sorter<Cat> sorter=new Sorter<Cat>();
            sorter.sort(cats, new CatComparator());
            System.out.println(Arrays.toString(cats));
        }
    
    }
    
    

    可以看到,我们在main函数中:

     sorter.sort(cats, new CatComparator());
    

    new CatComparator()传入了Cat类的比较策略,按照weight进行排序。如果想修改排序策略,只需要更改策略类即可。这便是策略模式。

    相关文章

      网友评论

        本文标题:java设计模式-策略模式(包含Comparable接口和泛型的

        本文链接:https://www.haomeiwen.com/subject/emipsktx.html