02 Strategy策略模式

strategy_策略模式-1

写一个排序类Sorter,写一个比较int类型方法;如果需要实现double类型的比较,就再写个double类型的方法;如果需要实现float类型的比较,就再写一个float类型的方法。
数值类型的很好比较,直接比较数值大小就可以了。
那么,如果想要比较自定义的类Cat,要怎么比较呢?重写排序方法,把int类型改成Cat类型?直接改是不行的,那就给Cat类提供一个比较的方法。

排序类 Sorter.java
package org.garen.strategy;

/**
 * 排序
 */
public class Sorter {

    /**
     * int类型排序
     * @param arr 数组
     */
    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);
        }
    }

    // double、float类型,把int替换一下就可以了,这里省略。。。

    /**
     * Cat类型排序
     * @param arr 数组
     */
    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);
        }
    }

    /**
     * 交换位置
     * @param arr int数组
     * @param i 数组下标
     * @param j 数组下标
     */
    static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    /**
     * 交换位置
     * @param arr Cat数组
     * @param i 数组下标
     * @param j 数组下标
     */
    static void swap(Cat[] arr, int i, int j) {
        Cat temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

猫类Cat.java
package org.garen.strategy;

/**
 * 猫
 */
public class Cat {
    int weight, height;     // 体重,身高

    /**
     * 构造函数
     * @param weight 体重
     * @param height 身高
     */
    public Cat(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }

    /**
     * 比较猫的大小
     * @param c 猫
     * @return 比较结果
     */
    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 +
                '}';
    }
}

测试类Main.java
package org.garen.strategy;

import java.util.Arrays;

/**
 * 测试类
 */
public class Main {
    public static void main(String[] args) {
        // int数组排序
        int[] a = {9, 2, 3, 5, 7, 1, 4};
        Sorter.sort(a);
        System.out.println(Arrays.toString(a));

        // Cat数组排序
        Cat[] b = {new Cat(5, 5), new Cat(3, 3), new Cat(1, 1)};
        Sorter.sort(b);
        System.out.println(Arrays.toString(b));
    }
}

运行结果:

[1, 2, 3, 4, 5, 7, 9]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]

strategy_策略模式-2

前面我们为了比较猫的大小,在Sorter类中写了比较猫的重载方法。那么我还需要比较狗,比较树,比较程序员,比较其它对象,那么每次都要在Sorter类中重载方法吗?
如果这个Sorter是JDK提供的,那每次程序员需要比较新的对象,都要联系Oracle公司,让他们的程序员帮忙在Sorter类中重载我们对象的比较方法吗?
开个玩笑,这肯定不可能的。
我们可以这样实现:Sorter中只提供一个sort方法,参数是Comparable,哪个类需要用这个sort方法,自己实现Comparable接口的compareTo方法就可以了。简单讲,哪个类需要用sort方法,哪个类自己提供一个比较的方法。

排序类 Sorter.java
package org.garen.strategy;

/**
 * 排序
 */
public class Sorter {

    /**
     * Cat类型排序
     * @param arr 数组
     */
    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);
        }
    }

    /**
     * 交换位置
     * @param arr Cat数组
     * @param i 数组下标
     * @param j 数组下标
     */
    static void swap(Comparable[] arr, int i, int j) {
        Comparable temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

猫类Cat.java
package org.garen.strategy;

/**
 * 猫
 */
public class Cat implements Comparable<Cat>{
    int weight, height;     // 体重,身高

    /**
     * 构造函数
     * @param weight 体重
     * @param height 身高
     */
    public Cat(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }

    /**
     * 实现Comparable接口,必须要重写compareTo方法
     * 比较猫的大小
     * @param c 猫
     * @return 比较结果
     */
    @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 +
                '}';
    }

}

狗类Dog.java
package org.garen.strategy;

/**
 * 狗
 */
public class Dog implements Comparable<Dog> {

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

}

测试类Main.java
package org.garen.strategy;

import java.util.Arrays;

/**
 * 测试类
 */
public class Main {

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

        // Cat数组排序
        Cat[] b = {new Cat(5, 5), new Cat(3, 3), new Cat(1, 1)};
        Sorter.sort(b);
        System.out.println(Arrays.toString(b));

        // Dog数组排序
        Dog[] c = {new Dog(3), new Dog(5), new Dog(2)};
        Sorter.sort(c);
        System.out.println(Arrays.toString(c));
    }

}

[1, 2, 3, 4, 5, 7, 9]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Dog{food=2}, Dog{food=3}, Dog{food=5}]

strategy_策略模式-3

前面只是进行铺垫,还没有真正用到策略模式。下面的例子开始用策略模式了。
我们定义一个比较器接口,该接口必须要实现compareTo方法。排序方法改成传入泛型数组和一个比较器。这样,同一个对象数组,传入不同比较器就可以按照不同的策略对数组进行排序。这样就是在使用策略模式了。

实体类

Cat.java

package org.garen.strategy;

/**
 * 猫
 */
public class Cat{
    int weight, height;     // 体重,身高

    /**
     * 构造函数
     * @param weight 体重
     * @param height 身高
     */
    public Cat(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }

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

}

Dog.java

package org.garen.strategy;

/**
 * 狗
 */
public class Dog {

    private int food;   // 饭量

    private int fur;    // 毛

    private int temper;     // 脾气

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

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

    public int getFood() {
        return food;
    }

    public void setFood(int food) {
        this.food = food;
    }
    
}

排序类Sorter.java
package org.garen.strategy;

/**
 * 排序
 */
public class Sorter<T> {

    /**
     * 排序
     * @param arr 数组
     */
    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.compareTo(arr[j], arr[minPos]) == -1 ? j : minPos;
            }

            swap(arr, i, minPos);
        }
    }

    /**
     * 交换位置
     * @param arr T类型数组
     * @param i 数组下标
     * @param j 数组下标
     */
    void swap(T[] arr, int i, int j) {
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

比较器

接口Comparator.java

package org.garen.strategy;

/**
 * 比较器
 */
public interface Comparator<T> {

    /**
     * 比较
     * @param t1 对象1
     * @param t2 对象2
     * @return 比较结果
     */
    int compareTo(T t1, T t2);

}

Integer比较器

package org.garen.strategy;

/**
 * 正序比较器
 */
public class IntegerAscComparator implements Comparator<Integer>{

    @Override
    public int compareTo(Integer t1, Integer t2) {
        if(t1 < t2) return -1;
        else if(t1 > t2) return 1;
        else return 0;
    }

}

package org.garen.strategy;

/**
 * 倒序比较器
 */
public class IntegerDescComparator implements Comparator<Integer>{

    @Override
    public int compareTo(Integer t1, Integer t2) {
        if(t1 > t2) return -1;
        else if(t1 < t2) return 1;
        else return 0;
    }

}

Cat比较器

package org.garen.strategy;

/**
 * 猫,重量比较器
 */
public class CatWeightComparator implements Comparator<Cat>{

    @Override
    public int compareTo(Cat t1, Cat t2) {
        if(t1.weight < t2.weight) return -1;
        else if(t1.weight > t2.weight) return 1;
        else return 0;
    }

}

package org.garen.strategy;

/**
 * 猫,身高比较器
 */
public class CatHeightComparator implements Comparator<Cat> {

    @Override
    public int compareTo(Cat t1, Cat t2) {
        if(t1.height < t2.height) return -1;
        else if(t1.height > t2.height) return 1;
        else return 0;
    }

}

Dog比较器

package org.garen.strategy;

public class DogFoodComparator implements Comparator<Dog>{

    @Override
    public int compareTo(Dog t1, Dog t2) {
        if(t1.getFood() < t2.getFood()) return -1;
        else if(t1.getFood() > t2.getFood()) return 1;
        else return 0;
    }

}

测试类

package org.garen.strategy;

import java.util.Arrays;

/**
 * 测试类
 */
public class Main {

    public static void main(String[] args) {
        // int数组排序
        Integer[] a = {9, 2, 3, 5, 7, 1, 4};
        // 策略:正序
        new Sorter<Integer>().sort(a, new IntegerAscComparator());
        System.out.println(Arrays.toString(a));
        // 策略:倒序
        new Sorter<Integer>().sort(a, new IntegerDescComparator());
        System.out.println(Arrays.toString(a));

        // Cat数组排序
        Cat[] b = {new Cat(5, 5), new Cat(3, 3), new Cat(1, 1)};
        // 策略:按照重量比较
        new Sorter<Cat>().sort(b, new CatWeightComparator());
        System.out.println(Arrays.toString(b));
        // 策略:按照身高比较
        new Sorter<Cat>().sort(b, new CatHeightComparator());
        System.out.println(Arrays.toString(b));

        // Dog数组排序
        Dog[] c = {new Dog(3), new Dog(5), new Dog(2)};
        // 策略:按照食量比较
        new Sorter<Dog>().sort(c, new DogFoodComparator());
        System.out.println(Arrays.toString(c));
        // 如果以后需要按照毛多少、性格温顺程度等排序,增加相应的比较器即可,不用动现有代码
    }

}

运行结果

[1, 2, 3, 4, 5, 7, 9]
[9, 7, 5, 4, 3, 2, 1]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Dog{food=2}, Dog{food=3}, Dog{food=5}]

可见,代码复杂度提高了。那么为什么还要用策略模式呢?
设计模式中有一个原则,开闭原则。即:对修改关闭,对新增开放。也就是说,写好的代码,尽量不去修改它,有新功能就写新的代码实现。
这样代码是累加的过程,不会对之前的代码有影响,版本升级仍然可以兼容旧版本。
扩展性强,比如狗的排序,如果以后需要按照毛多少、性格温顺程度等排序,增加相应的比较器即可,不用动现有代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值