Java设计模式之策略模式

参考自马士兵设计模式源码

gitee链接

我的理解是不同对象有不同的处理策略

比如有一个排序工具类Sorter,它的作用就是将传进来的数组进行排序,像这样:

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] == -1 ? j : minPos;
            }

            swap(arr, i, minPos);
        }
    }

    private static void swap(int[] arr, int i, int minPos) {
        int temp = arr[i];
        arr[i] = arr[minPos];
        arr[minPos] = temp;
    }
}
复制代码

这个排序工具类有一个问题,就是仅支持int数组,如果需要被处理的是Object对象等类型就不行了,所以让我们来一步一步用策略模式来改造一下。

首先新建两个用于测试的类CatDog

package com.cc.strategy;

public class Cat {
    int weight, height;

    public Cat(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "weight=" + weight +
                ", height=" + height +
                '}';
    }
}
复制代码
package com.cc.strategy;

public class Dog {
    int food;

    public Dog(int food) {
        this.food = food;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "food=" + food +
                '}';
    }
}
复制代码

其中Cat有两个属性,重量weight和高度height,Dog有一个饭量food。

首先我们希望Sorter类可以做到,将Cat数组根据weight排序,那么我们可以这样写:

新建一个比较的实现类Comparable(我知道Java已经有这个实现类了,但是为了加深理解,让我们手撸一个吧):

package com.cc.strategy;

public interface Comparable<T> {
    int compareTo(T o);
}
复制代码

其中泛型T可能会有疑惑,后面会提到,

为了支持Sorter排序,Cat需要实现这个Comparable类,修改后如下:

package com.cc.strategy2;

// 上面提到的泛型可以在此处指定...
public class Cat implements Comparable<Cat> {
    int weight, height;

    public Cat(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }

    /**
     * ...然后本来是T o格式,使用了泛型并且在类上指定之后可以在实现函数中直接用Cat c的方式指定
     * 这样其实是自动做了一层转换:Object o => Cat c
     * 如果不用泛型,就要这样多写一行:
     *  Cat c = (Cat)o;
     */
    @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 +
                '}';
    }
}
复制代码

Sorter排序类也要修改,从原来只接受int[]变成Comparable[],即所有实现了Comparable的对象:

package com.cc.strategy2;

public class Sorter {
    public 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);
        }
    }

    private void swap(Comparable[] arr, int i, int minPos) {
        Comparable temp = arr[i];
        arr[i] = arr[minPos];
        arr[minPos] = temp;
    }
}
复制代码

测试一下;

package com.cc.strategy;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        Cat[] c = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
        Sorter sorter = new Sorter();
        sorter.sort(c);
        System.out.println(Arrays.toString(c));
    }
}
复制代码

结果:

[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
复制代码

Cat类的排序已经完成了,当我们想对Dog也进行排序的话,参照Cat类即可:

package com.cc.strategy;

public class Dog implements Comparable<Dog> {
    int food;

    public Dog(int food) {
        this.food = food;
    }

    @Override
    public int compareTo(Dog d) {
        if (this.food < d.food) {
            return -1;
        } else if (this.food > d.food) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public String toString() {
        return "Dog{" +
                "food=" + food +
                '}';
    }
}
复制代码

现在还有一个问题,Cat的排序,我们是在Cat类的实现函数compareTo()中根据weight来排的,Cat有两个属性weight和height,当我们想让Cat变成按照height排序的话怎么办呢?修改实现函数compareTo()是肯定不行的,这样一点也不灵活,现在终于轮到策略模式出场了,是的,前面的都不是策略模式,只是铺垫。

让我们来新建一个比较实现类Comparator:

package com.cc.strategy;

public interface Comparator<T> {
    int comare(T o1, T o2);
}
复制代码

现在可以开始疑惑了,这个Comparator和刚刚的Comparable有什么区别呢?

答:在Java中,Comparable是排序接口,如果一个类实现了Comparable接口,表示该类支持排序,就像我们在Sorter中实现的,实现类Comparable的对象通过compareTo()方法进行排序,返回1,-1或者0;

而Comparator是比较接口,通常是用于一种比较方法的实现,听到这里可能还是不理解,没关系我们接着看。


在刚刚,Cat是通过weight排序的,为了让Cat能够灵活一些,既可以根据weight排序,也可以根据height排序,我们新建两个比较类:

package com.cc.strategy;

public class CatHeightComparator implements Comparator<Cat> {
    @Override
    public int comare(Cat o1, Cat o2) {
        if (o1.height < o2.height) {
            return 1;
        } else if (o1.height > o2.height) {
            return -1;
        } else {
            return 0;
        }
    }
}
复制代码
package com.cc.strategy;

public class CatWeightComparator implements Comparator<Cat> {
    @Override
    public int comare(Cat o1, Cat o2) {
        if (o1.weight < o2.weight) {
            return -1;
        } else if (o1.weight > o2.weight) {
            return 1;
        } else {
            return 0;
        }
    }
}
复制代码

这两个比较类实现了Comparator的compare()方法,并且分别实现了比较方式,现在改造一下Sorter排序类:

package com.cc.strategy;

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.comare(arr[j], arr[minPos]) == -1 ? j : minPos;
            }

            swap(arr, i, minPos);
        }
    }

    private void swap(T[] arr, int i, int minPos) {
        T temp = arr[i];
        arr[i] = arr[minPos];
        arr[minPos] = temp;
    }
}
复制代码

现在,可以将原来Cat关于Comparable实现类的代码删掉,留下一个干净的对象了,因为排序实现我们放在了CatHeightComparator和CatWeightComparator中:

package com.cc.strategy;

public class Cat {
    int weight, height;

    public Cat(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "weight=" + weight +
                ", height=" + height +
                '}';
    }
}
复制代码

测试一下:

package com.cc.strategy;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        Cat[] c = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};

        Sorter<Cat> catSorter = new Sorter<>();

        catSorter.sort(c, new CatWeightComparator());
        System.out.println(Arrays.toString(c));
        
        catSorter.sort(c, new CatHeightComparator());
        System.out.println(Arrays.toString(c));
    }
}
复制代码

结果:

[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Cat{weight=5, height=5}, Cat{weight=3, height=3}, Cat{weight=1, height=1}]
复制代码

大功告成,Sorter排序类可以对传入的对象数组,根据不同的排序策略而进行不一样的排序,这就是策略模式的妙用,虽然代码多了一些,但是维护性是很高的,当我们想对Dog类或者更多的类进行排序操作时,只需要为其新建一个排序策略即可。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值