Java 设计模式中的策略模式详情

 更新时间:2022年09月25日 10:58:10   作者:我赢了算我输  
这篇文章主要介绍了Java 设计模式中的策略模式详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

策略模式的应用场景

策略模式是否要使用,取决于业务场景是否符合,有没有必要。

是否符合

如果业务是处于不同的场景时,采取不同的处理方式的话,就满足符合。 这里举几个业务栗子

如果今天我有1000块,那我就和朋友去游乐园玩、然后再去吃顿好吃的。如果有2000块的话,那我就先买一件好看的衣服,再和朋友去游乐园玩和吃好吃的商品收银业务,根据店中不同的活动分为正常收费、折扣收费、返利收费,每种收费的方式都不一样接收某安全设备的数据的时候,根据发过来不同的数据类型,执行设备报警、设备指定信息存储、设备本身状态信息修改等等的处理方式

这里上面三种业务场景都符合处于不同的场景时,采取不同的处理方式

有没有必要

这里等描述完例子后,再回到这个问题

例子

这里采用上面第三个例子的业务分别进行编写不用策略模式和用策略模式的效果

不用策略模式

public class Main {
    public static void main(String[] args) {
        //设备报警
        int deviceDataType=2;
        DeviceData deviceData=new DeviceData();
        deviceData.setName("安全设备A");

        switch (deviceDataType){
            case 1:
                DeviceCallPolice(deviceData);
                break;
            case 2:
                DeviceStatus(deviceData);
                break;
            default:
                System.out.println("没有相关的策略");
                break;
        }

    }
    private static void DeviceStatus(DeviceData deviceData) {
        System.out.println("正在修改"+deviceData.getName()+"状态为指定状态");
        System.out.println("正在记录本次修改状态的时间信息");
        System.out.println("根据修改后的状态判断是否要通知相关人");
    }
    private static void DeviceCallPolice(DeviceData deviceData) {
        System.out.println("正在修改"+deviceData.getName()+"状态为报警状态");
        System.out.println("正在记录本次报警时间信息");
        System.out.println("设备相关人的短信通知");
    }

}

效果:

使用策略模式

策略上下文

/**
 * 
 * 安全设备处理上下文
 */
public class SafetyDeviceContext {

    private DeviceHandlerStrategy deviceHandlerStrategy;

    public SafetyDeviceContext(int dataType){
        switch (dataType){
            case 1:
                deviceHandlerStrategy=new DeviceCallPoliceStrategy();
                break;
            case 2:
                deviceHandlerStrategy=new DeviceStatusStrategy();
                break;
            default:
                System.out.println("没有相关的策略");
                break;
        }

    }
    public void Handler(DeviceData deviceData){

        deviceHandlerStrategy.handler(deviceData);
    }
}

策略接口以及具体实现类

/**
 * 设备处理策略
 */
public interface DeviceHandlerStrategy {

    void handler(DeviceData deviceData);
}
/**
 * 安全设备报警策略
 */
public class DeviceCallPoliceStrategy implements DeviceHandlerStrategy {

    @Override
    public void handler(DeviceData deviceData) {

        System.out.println("正在修改设备状态为报警状态");
        System.out.println("正在记录本次报警时间信息");
        System.out.println("设备相关人的短信通知");
    }
}
/**
 * 设备状态修改策略
 */
public class DeviceStatusStrategy implements DeviceHandlerStrategy {

    @Override
    public void handler(DeviceData deviceData) {
        System.out.println("正在修改设备状态为指定状态");
        System.out.println("正在记录本次修改状态的时间信息");
        System.out.println("根据修改后的状态判断是否要通知相关人");
    }
}

Main类

public class Main {

    public static void main(String[] args) {
        //设备报警
        int deviceDataType=2;
        DeviceData deviceData=new DeviceData();
        deviceData.setName("安全设备A");
        SafetyDeviceContext safetyDeviceContext=new SafetyDeviceContext(deviceDataType);
        safetyDeviceContext.handler(deviceData);
    }
}

效果:

两种方式的不同

从简易和易懂程度来说,自然是不用策略模式好一些,用策略模式会导致类的增多,而且如果不懂策略模式的人去看代码时可读性不高。但使用策略模式胜于可扩展性和可维护性要强于不用策略模式的

使用策略模式在Main函数(使用方),消除了类型的swich判断,把这些判断放到了Context,使用方调用的时候,就不必过多关心设备处理策略,只需要把值传进Context就好了。

之前我很不理解策略模式为什么能避免使用多重条件判断,因为上面的写法只是把判断的代码移到了Context而已,要写的判断还是要写,直到我知道了采用字典和反射的方式时,就理解了,往下会说

  • 如果后续我们要添加一种"设备定时报告信息"业务处理方式时,使用策略模式那种只需要在Context添加一层case(也可以不需要,可以用反射的方式)和添加一个策略的实现类就好了,而不用策略模式需要在原来使用方的代码添加一层case,可能会影响到原来的业务稳定性。
  • 算法独立出来也方便我们使用单元测试进行测试

策略模式有没有必要使用?

策略模式的目的是减少具体的算法方式使用方式之间的耦合,避免多重if判断,并让具体的算法方法尽可能独立。所以实现的时候,必然成本会高一些。因此我们要使用策略模式的时候,要确定该业务业务本身是否复杂,后续是不是会时不时添加其他的处理方式
例如上面的第三个例子,设备对应的处理措施本身具备了复杂性,例如会涉及数据本身的处理、设备状态的更改、设备事件的触发等等处理措施,而且后续因业务的扩展,可能会添加不同的设备场景,不同的设备处理方式。像这种就可以考虑使用

如何避免Context类使用判断逻辑

可以采用字典+反射的方式进行避免

定义策略字典的全局变量

/**
 * 设备处理策略方式字典
 */
public class DeviceStrategyDictionary {
    public static HashMap<Integer,String> dictionary=new HashMap<>();

}

修改Context的代码

import java.util.HashMap;

/**
 * 安全设备处理上下文
 */
public class SafetyDeviceContext {

    private DeviceHandlerStrategy deviceHandlerStrategy;

    public SafetyDeviceContext(int dataType) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        HashMap<Integer,String> dic= DeviceStrategyDictionary.dictionary;
        if(!dic.containsKey(dataType)){
            System.out.println("不包含该处理方式");
        }
        //使用反射的方式
        Class<?> fz=Class.forName(dic.get(dataType));
        deviceHandlerStrategy=(DeviceHandlerStrategy) fz.newInstance();

    }
    public void handler(DeviceData deviceData){

        deviceHandlerStrategy.handler(deviceData);
    }
}

Main方法

public class Main {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

        //程序启动的时候
        DeviceStrategyDictionary.dictionary.put(1,"DeviceCallPoliceStrategy");
        DeviceStrategyDictionary.dictionary.put(2,"DeviceStatusStrategy");

        //设备报警
        int deviceDataType=2;
        DeviceData deviceData=new DeviceData();
        deviceData.setName("安全设备A");

        SafetyDeviceContext safetyDeviceContext=new SafetyDeviceContext(deviceDataType);

        safetyDeviceContext.handler(deviceData);
    }

}

效果:

这样就可以避免使用if判断了,不过反射也有相关的性能消耗,这点也需要做权衡。

到此这篇关于Java 设计模式中的策略模式详情的文章就介绍到这了,更多相关Java 策略模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java查找字符串中的包含子字符串的个数实现代码

    java查找字符串中的包含子字符串的个数实现代码

    下面小编就为大家带来一篇java查找字符串中的包含子字符串的个数实现代码。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • 把Jar文件转成exe安装文件的实现方法

    把Jar文件转成exe安装文件的实现方法

    下面小编就为大家带来一篇把Jar文件转成exe安装文件的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • SpringBoot+OCR 实现图片文字识别

    SpringBoot+OCR 实现图片文字识别

    本文主要介绍了SpringBoot+OCR 实现图片文字识别,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • MyBatis 多个条件使用Map传递参数进行批量删除方式

    MyBatis 多个条件使用Map传递参数进行批量删除方式

    这篇文章主要介绍了MyBatis 多个条件使用Map传递参数进行批量删除方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • 详解SpringBoot中@NotNull,@NotBlank注解使用

    详解SpringBoot中@NotNull,@NotBlank注解使用

    这篇文章主要为大家详细介绍了Spring Boot中集成Validation与@NotNull,@NotBlank等注解的简单使用,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-08-08
  • Java中的ScheduledThreadPoolExecutor定时任务详解

    Java中的ScheduledThreadPoolExecutor定时任务详解

    这篇文章主要介绍了Java中的ScheduledThreadPoolExecutor详解,  ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor,它主要用来在给定的延迟之后运行任务,或者定期执行任务,ScheduledThreadPoolExecutor 的功能与 Timer 类似<BR>,需要的朋友可以参考下
    2023-12-12
  • 详解Java中Dijkstra(迪杰斯特拉)算法的图解与实现

    详解Java中Dijkstra(迪杰斯特拉)算法的图解与实现

    Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。本文将详解该算法的图解与实现,需要的可以参考一下
    2022-05-05
  • 如何为Spring Cloud Gateway加上全局过滤器

    如何为Spring Cloud Gateway加上全局过滤器

    这篇文章主要介绍了如何为Spring Cloud Gateway加上全局过滤器,帮助大家更好得理解和学习使用Gateway,感兴趣的朋友可以了解下
    2021-03-03
  • Java字符串拼接新方法 StringJoiner用法详解

    Java字符串拼接新方法 StringJoiner用法详解

    在本篇文章中小编给大家分享的是一篇关于Java字符串拼接新方法 StringJoiner用法详解,需要的读者们可以参考下。
    2019-09-09
  • Spring Boot应用Docker化的步骤详解

    Spring Boot应用Docker化的步骤详解

    这篇文章主要给大家介绍了关于Spring Boot应用Docker化的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04

最新评论