【设计模式】2、策略模式 Strategy

策略模式 Strategy

1、什么叫策略模式

首先:策略模式属于行为模式

指的是对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

策略模式组成:
  • 抽象策略角色: 策略类,通常由一个接口或者抽象类实现。

  • 具体策略角色:包装了相关的算法和行为

  • 环境角色:持有一个策略类的引用,最终给客户端调用

2、为什么要用策略模式

优点:

1、 策略模式将公共代码提取到父类,从而避免重复的代码。

2、将行为业务逻辑和算法实现逻辑剥离出来降低耦合性

3、符合开闭原则,提高扩展性

缺点

1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。

2、 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

3、java接口介绍

3.1、Interface Comparable
//java.lang包下
int compareTo(T o)

方法介绍:

Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

将此对象与指定对象进行顺序比较。当此对象小于、等于或大于指定对象时,返回负整数、零或正整数。

3.2、Interface Comparator
//java.util
int compare(T o1,T o2)

方法介绍:

Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

比较其两个参数的顺序。当第一个参数小于、等于或大于第二个参数时,返回负整数、零或正整数。

4、示例代码

4.1、原始示例

定义一个交换算法:

/**
 * 进行排序
 */
public class MySort {

    //简单到选择排序
    public void Sort(int[] arr){
        //遍历趟数
        for (int i = 0; i < arr.length; i++) {
            //寻找最小的一个数
            for (int j = i+1; j < arr.length; j++) {
                //找到最小到一个,返回下标
                int minIndex = arr[i] < arr[j] ? i : j;
                // 直接将第i个替换成最小的,便于下次比较替换
                swap(arr,i,minIndex);
            }

        }
    }

    //交换
    public void swap(int[] arr,int i,int minIndex){
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

测试一下:

@SpringBootTest
public class MySortTest {
    @Test
    void Sort(){
        int[] a = {3,5,2,1,9,6,8};
        MySort mySort = new MySort();
        mySort.Sort(a);
        for (int i : a) {
            System.out.print(i);
        }
    }
}

测试结果
测试结果
测试没问题。

4.2、问题

如果想要换成float类型排序怎么解决,如果我们用其他类,比如一个用户类怎么排序。

4.3、Comparable接口实现

首先我们调整一下我们的排序类,让他可以实现多种类的排序,那么我们可以参数必须是Comparable类型的数组,这样以来不管是什么类型的排序,他一定会去实现一个方法compareTo用来定义比较规则,MySort类修改

/**
 * 进行排序
 */
public class MySort {

    //简单到选择排序
    public void Sort(Comparable[] arr){
        //遍历趟数
        for (int i = 0; i < arr.length; i++) {
            //寻找最小的一个数
            for (int j = i+1; j < arr.length; j++) {
                //找到最小到一个,返回下标
                int minIndex = arr[i].compareTo(arr[j])==-1 ? i : j;
                // 直接将第i个替换成最小的,便于下次比较替换
                swap(arr,i,minIndex);
            }

        }
    }

    //交换
    public void swap(Comparable[] arr,int i,int minIndex){
        Comparable temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

比如定义一个users类给用户类排序,用户类去实现Comparable接口

public class Users implements Comparable<Users>{

    private String name;

    //年龄
    private Integer age;

    //身高
    private Integer height;

    public Users(String name, Integer age, Integer height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public Users() {
    }

    @Override
    public int compareTo(Users o) {
        if (this.age < o.getAge()) return -1;
        else if (this.age > o.getAge()) return 1;
        else return 0;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getHeight() {
        return height;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Users{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}

测试

@SpringBootTest
public class MySortTest {
    @Test
    void Sort(){
//        float[] a = {3,5,2,1,9,6,8};
        Users[] a = {
                new Users("a",1,1),
                new Users("c",3,3),
                new Users("e",5,5),
                new Users("d",4,4),
                new Users("b",2,2),
        };
        MySort mySort = new MySort();
        mySort.Sort(a);
        for (Users i : a) {
            System.out.print(i);
        }
    }
}

结果正常排序:
在这里插入图片描述

这样以来我们不需要改变排序类,想要在给其他类进行排序我们就直接让其实现Comparable接口即可。

那么问题又来了,如果当前用户类还想用身高来进行排序又该怎么办呢?

这个时候我们就需要用到策略模式了

5、策略模式实现

5.1、Comparator接口

上面我们说到用户类想用年龄进行排序,还想用身高进行排序,这个时候我们就可以使用策略模式了,这里我们使用Comparator接口来实现

首先我们看一下排序类:

/**
 * 进行排序
 */
public class MySort {

    //简单到选择排序
    public void Sort(Object[] arr, Comparator comparator){
        //遍历趟数
        for (int i = 0; i < arr.length; i++) {
            //寻找最小的一个数
            for (int j = i+1; j < arr.length; j++) {
                //找到最小到一个,返回下标
                int minIndex = comparator.compare(arr[i],arr[j])==-1 ? i : j;
                // 直接将第i个替换成最小的,便于下次比较替换
                swap(arr,i,minIndex);
            }

        }
    }

    //交换
    public void swap(Object[] arr,int i,int minIndex){
        Object temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

我们的排序方法要传递两个参数,一个是我们要排序的数组,一个是实现Comparator的策略方式

只要实现了Comparator接口的策略一定会存在一个compare方法来进行比较

在看一下我们的用户类

package com.summy.entity;

import lombok.Data;

import java.util.Comparator;

public class Users{

    private String name;

    //年龄
    private Integer age;

    //身高
    private Integer height;

    public Users(String name, Integer age, Integer height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public Users() {
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getHeight() {
        return height;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Users{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }

}

单纯的定义我们的用户类就好了不用去实现任何的接口,降低了耦合性

然后我们要定义我们的策略类

根据用户年龄来定义策略

package com.summy.strategy;

import com.summy.entity.Users;

import java.util.Comparator;

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

根据身高来定义策略

package com.summy.strategy;

import com.summy.entity.Users;

import java.util.Comparator;

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

我们来测试一下

@SpringBootTest
public class MySortTest {
    @Test
    void Sort(){
//        float[] a = {3,5,2,1,9,6,8};
        Users[] a = {
                new Users("a",1,1),
                new Users("c",3,3),
                new Users("e",5,5),
                new Users("d",4,4),
                new Users("b",2,2),
        };
        MySort mySort = new MySort();
        mySort.Sort(a, new UsersHeightStrategy());
        for (Users i : a) {
            System.out.print(i);
        }
    }
}

其他的不变,只要将我们的策略传递进去即可,上面是根据身高排序,如果想换回年龄,我们只需要在mySort.Sort(a, new UsersHeightStrategy());改为mySort.Sort(a, new UsersAgeStrategy());即可。

我们在实际工作场景中,可以自定义策略类接口,定义相应策略实现就ok了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值