设计模式之策略模式(Strategy)

设计模式之策略模式


在jdk1.8之后,为了和之前的接口进行兼容,接口里面必须方法实现,因为要支持lambda表达式。

comparator接口,就是用到了策略模式

在这里插入图片描述

同样,java.lang中的comparable接口,也是策略模式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

环境准备

初始化

  • 定义一个排序工具(选择排序法),再定义一个其他类,自定义一个int类型的数组,调用sort方法。
package com.cyc.design.strategy;

import java.util.Arrays;

/**
 * @author chenyunchang
 * @version 1.0
 * @date 2021/6h/1 15:05
 * @Description: 主方法
 */
public class Main {
    public static void main(String[] args) {
        int[] a = {9, 2, 3, 5, 7, 1, 4};
        Sorter sorter = new Sorter();
        sorter.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

package com.cyc.design.strategy;

/**
 * @author fei
 * 选择法排序
 */
public class Sorter {

    public void sort(int[] arr) {
        for (int i = 0; i < arr.length - 1; 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;
    }
}

  • 输出结果
[1, 2, 3, 4, 5, 7, 9]

Process finished with exit code 0
  • 思考:这里要排序的是int数组,如果要排序double数组,还要再写一遍double类型的排序算法吗?同样的算法实现好多遍?

尝试变通

  • 新建一个类,Cat,有体重,身高属性,里面写一个compareTo方法
package com.cyc.design.strategy;

/**
 * @author chenyunchang
 * @version 1.0
 * @date 2021/6/1 15:36
 */
public class Cat {
    int weight, 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 +
                '}';
    }
}

  • 改造sort方法
package com.cyc.design.strategy;

/**
 * @author fei
 * 选择法排序
 */
public class Sorter {

    public void sort(Cat[] arr) {
        for (int i = 0; i < arr.length - 1; 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;
    }
}

改写main方法

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

执行main方法,输出结果

[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]

现在cat是可以被排序了, 但是如果以后有了dog,rabbit…,依然要重写一个sort。

换个方向

  1. 定义一个接口,Comparable
package com.cyc.design.strategy;

/**
 * @author fei
 */
public interface Comparable {
    int compareTo(Object o);
}

  1. Cat实现Comparable接口

改造Cat里面的compareTo方法

    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;
        }
    }

compareTo,入参改为Object类型,然后再下面进行cat的强制转换

  1. 新建一个Dog类,实现Comparable方法
package com.cyc.design.strategy;

/**
 * @author chenyunchang
 * @version 1.0
 * @date 2021/6/1 16:10
 */
public class Dog implements Comparable{
    int food;

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


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

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

  1. 改造sort方法
package com.cyc.design.strategy;

/**
 * @author fei
 * 选择法排序
 */
public class Sorter {

    public void sort(Comparable[] arr) {
        for (int i = 0; i < arr.length - 1; 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;
    }
}

  1. main方法
    public static void main(String[] args) {
//        int[] a = {9, 2, 3, 5, 7, 1, 4};
//        Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
        Dog[] a = {new Dog(3), new Dog(5), new Dog(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=5, height=5}]
[Dog{food=1}, Dog{food=3}, Dog{food=5}]

问题:如果cat的compareTo方法,传入的不是Cat类型的参数,那么此处强制转换便会报错。

优化

利用jdk1.5的新特性,泛型,comparable接口里指定一个泛型的参数

改造的代码如下


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


public class Cat implements Comparable<Cat>{
    int weight, height;

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

    @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 +
                '}';
    }
}


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

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


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

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

– 可是这种模式依然不够灵活,猫比较大小的策略可能不止这一种,如果比较大小的方式也能灵活配置就好了。

设计模式中,有一种开闭原则,对修改关闭,对扩展开放。

接下来,开始策略模式

策略模式

  1. 新建一个Comparator接口
package com.cyc.design.strategy;

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

  1. 改造Sorter的sort方法

public class Sorter<T> {

    public void sort(T[] arr, Comparator<T> comparator) {
        for (int i = 0; i < arr.length - 1; 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;
    }
}

  1. 新建一个DogComparator
public class DogComparator implements Comparator<Dog> {
    @Override
    public int compare(Dog o1, Dog o2) {
        if(o1.food < o2.food) {
            return -1;
        } else if (o1.food > o2.food) {
            return 1;
        } else {
            return 0;
        }
    }
}

  1. main方法
public class Main {
    public static void main(String[] args) {
//        int[] a = {9, 2, 3, 5, 7, 1, 4};
//        Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
        Dog[] a = {new Dog(3), new Dog(5), new Dog(1)};
        Sorter<Dog> sorter = new Sorter<>();
        sorter.sort(a,new DogComparator());
        System.out.println(Arrays.toString(a));
    }
}

  1. 输出结果
[Dog{food=1}, Dog{food=3}, Dog{food=5}]

此时效果不够明显,当一个类有多中比较方式的时候。即一个类可以有多种比较策略

例如: 猫,根据身高和体重分别比较大小

新建一个猫身高比较器和体重比较器

public class CatHeightComparator implements Comparator<Cat> {
    @Override
    public int compare(Cat o1, Cat o2) {
        if (o1.height > o2.height) {
            return -1;
        } else if (o1.height < o2.height) {
            return 1;
        } else {
            return 0;
        }
    }
}

public class CatHeightComparator implements Comparator<Cat> {
    @Override
    public int compare(Cat o1, Cat o2) {
        if (o1.height > o2.height) {
            return -1;
        } else if (o1.height < o2.height) {
            return 1;
        } else {
            return 0;
        }
    }
}

main方法

public class Main {
    public static void main(String[] args) {
//        int[] a = {9, 2, 3, 5, 7, 1, 4};
        Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
//        Dog[] a = {new Dog(3), new Dog(5), new Dog(1)};
        Sorter<Cat> sorter = new Sorter<>();
        sorter.sort(a,new CatWeightComparator());
//        sorter.sort(a,new CatHeightComparator());
        System.out.println(Arrays.toString(a));
    }
}

当按照体重比较时,输出结果为

[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}]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

意田天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值