设计模式之策略模式

策略模式

从comparator与comparable谈起

先从最基本的讲起,定义一个Sorter类,sort方法是选择排序的实现,实现对int数组a排序:

public class Sorter {
    public void sort(int[] a)
    {
        for (int i=0;i<a.length;i++)
        {
            int minPos = i;
            for (int j = i; j < a.length; j++) 
                minPos = a[j] < a[minPos] ? j : minPos;
            int t = a[i];
            a[i] = a[minPos];
            a[minPos] = t;
        }
    }
}

再写个主函数,实现调用sort对a数组排序:

public class Main {
    public static void main(String[] args) {
        int[] a = {4,3,5,1,6,9,2};
        Sorter sorter = new Sorter();
        sorter.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

现在思考一个问题:如果要是对Double类型的数组进行排序该怎么做呢?首先想到的就是重载一下sort,让它可以接受Double类型的数组,那如果想对Dog类,Cat类,Car类进行排序呢?每一个都要重写一次吗?麻不麻烦的先不提,但就sort那段代码重复这么多次,就很不友好。此时我们可以写一个接口:


public interface Comparable {
	//这里的参数暂时用Object
    int CompareTo(Object o);
}

然后我们写一个Cat类,并实现Comparable接口,重写CompareTo方法,实现Cat按照weight排序:

public class Cat implements Comparable{
    int weight,height;

    public Cat(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }
    @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;
        return 0;
    }
}

修改我们的sort函数,修改参数为Comparable接口类型,这样的目的是只要我们实现Comparable接口的类,都可以用这个函数进行排序:

public void sort(Comparable[] a)
{
    for (int i=0;i<a.length;i++)
    {
        int minPos = i;
        for (int j = i; j < a.length; j++)
            //修改 a[j].CompareTo(a[minPos])
            minPos = a[j].CompareTo(a[minPos])==-1 ? j : minPos;
        Comparable t = a[i];
        a[i] = a[minPos];
        a[minPos] = t;
    }
}

主函数:

public class Main {
    public static void main(String[] args) {
        Cat[] a = {new Cat(3,3),new Cat(4,4),new Cat(1,1)};
        Sorter sorter = new Sorter();
        sorter.sort(a);
        System.out.println(Arrays.toString(a));
    }
}
//输出:[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=4, height=4}]

可以看到已经对Cat进行了排序,之后我们如果想要对Dog排序,对Person排序,只要实现Comparable接口就可以。

再进一步思考:如果我想按照Cat的height排序,怎么办?答案是需要修改Cat类中CompareTo方法,那如果以后我想按照其他的排序呢?是不是每次都要修改CompareTo方法?这样依旧很麻烦

下面正式引入策略模式,

此时我们可以声明一个比较器接口:

public interface Comparator {
    //暂时使用Object
    int Compare(Object o1,Object o2);
}

然后我们声明一个Cat比较器类实现Comparator接口:

public class CatComparator implements Comparator{
    @Override
    public int Compare(Object o1, Object o2) {
        Cat c1 = (Cat) o1;
        Cat c2 = (Cat) o2;
        if (c1.height<c2.height)
            return -1;
        else if (c1.height>c2.height)
            return 1;
        return 0;
    }
}

现在我们再次修改sort函数:

public void sort(Comparable[] a,Comparator comparator)
{
    for (int i=0;i<a.length;i++)
    {
        int minPos = i;
        for (int j = i; j < a.length; j++)
            minPos = comparator.Compare(a[j],a[minPos])==-1 ? j : minPos;
        Comparable t = a[i];
        a[i] = a[minPos];
        a[minPos] = t;
    }
}

我们在主函数中声明一个比较器传入sort函数:

public static void main(String[] args) {
    Cat[] a = {new Cat(3,3),new Cat(4,4),new Cat(1,1)};
    Sorter sorter = new Sorter();
    sorter.sort(a,new CatComparator());
    System.out.println(Arrays.toString(a));
}

这样做的好处就是,程序更加灵活,具有了更强的可扩展性,当我们需要按照别的属性进行排序的时候,只需要新建一个类,而不是去修改代码,这样做符合了开闭原则。

代码中还有不尽人意的地方,那就是Object,每次使用都需要强转类型,写起来很是麻烦,所以我们修改为泛型:

Comparator接口:

public interface Comparator<T> {
    int Compare(T o1,T o2);
}

sort函数:

public class Sorter<T> {
    public void sort(T[] a,Comparator<T> comparator)
    {
        for (int i=0;i<a.length;i++)
        {
            int minPos = i;
            for (int j = i; j < a.length; j++)
                minPos = comparator.Compare(a[j],a[minPos])==-1 ? j : minPos;
            T t = a[i];
            a[i] = a[minPos];
            a[minPos] = t;
        }
    }
}

CatComparator:

public class CatComparator implements Comparator<Cat>{
    @Override
    public int Compare(Cat c1, Cat c2) {
        if (c1.height<c2.height)
            return -1;
        else if (c1.height>c2.height)
            return 1;
        return 0;
    }
}

main:

public static void main(String[] args) {
    Cat[] a = {new Cat(3,3),new Cat(4,4),new Cat(1,1)};
    Sorter<Cat> sorter = new Sorter<>();
    sorter.sort(a,new CatComparator());
    System.out.println(Arrays.toString(a));
}

因为Comparator是函数式接口,所以我们可以直接使用lambda表达式:

public static void main(String[] args) {
    Cat[] a = {new Cat(3,3),new Cat(4,4),new Cat(1,1)};
    Sorter<Cat> sorter = new Sorter<>();
    sorter.sort(a,(o1,o2)->{
        if (o1.height>o2.height) return -1;
        else if (o1.height<o2.height) return 1;
        return 0;
    });
    System.out.println(Arrays.toString(a));
}

当我们需要进行按照不同类不同策略进行排序的时候,只需要声明新的XXXComparator类就可以了,其他的源码都不用改动,增强了可扩展性,这就是策略模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值