【设计模式】策略模式在Java工程中应用

news2024/12/27 17:11:30

在之前的文章中,曾经给大家介绍过策略模式:【设计模式】策略模式,在该篇文章中,我们曾很清楚的说到,策略模式主要解决的问题是:在有多种算法相似的情况下,解决使用 if...else 所带来的复杂和难以维护。策略模式使我们的实现更加符合开闭原则:面向扩展开发,面向修改关闭。在后来的学习和工作的多次应用中,有了更加深刻的认识。再次总结此篇文章赘述下。

此篇文章,将以创建订单为例,创建不同类型的订单,不同类型的订单不同的处理逻辑。

类图:

代码:

  1. 抽象策略(Strategy)角色:抽象策略角色由抽象类或接口来承担,它给出具体策略角色需要实现的接口;

package strategyTest;

import strategyTest.dto.BaseRequestDTO;

/**
 * 类 名 称:CreateStrategy
 * 类 描 述:策略抽象类
 * 创建时间:2023/2/20 3:46 下午
 * 创 建 人:admin
 */
public abstract class AbstractOrderStrategy {
    public abstract Boolean isPracticable(BaseRequestDTO dto);

    // 业务执行总流程
    public ResponseResult process(BaseRequestDTO dto) {
        ResponseResult paramsValidate = validateParams(dto);
        if (!paramsValidate.isSuccess()) {
            return paramsValidate;
        }
        ResponseResult ruleValidate = validateRules(dto);
        if (!ruleValidate.isSuccess()) {
            return ruleValidate;
        }
        ResponseResult processResult = doProcess(dto);
        if(processResult.isSuccess()){
            postProcessAction(dto);
        }
        return processResult;
    }

    // 参数校验
    protected abstract ResponseResult validateParams(BaseRequestDTO dto);

    // 业务规则校验
    protected abstract ResponseResult validateRules(BaseRequestDTO dto);

    // 核心实现
    protected abstract ResponseResult doProcess(BaseRequestDTO dto);

    // 后置处理(异步操作等)
    protected abstract void postProcessAction(BaseRequestDTO dto);
}

2.具体策略(ConcreteStrategy)角色:实现封装了具体的算法或行为;

顺风车类型处理:

package strategyTest.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import strategyTest.AbstractOrderStrategy;
import strategyTest.ResponseResult;
import strategyTest.dto.BaseRequestDTO;
import strategyTest.dto.SfcRequestDTO;

/**
 * 类 名 称:SfcImpl
 * 类 描 述:TODO
 * 创建时间:2023/2/20 3:58 下午
 * 创 建 人:admin
 */
@Service
public class SfcImpl extends AbstractOrderStrategy {
    private Logger logger = LoggerFactory.getLogger(SfcImpl.class);
    @Override
    public Boolean isPracticable(BaseRequestDTO dto) {
        if(dto.getType() == 1){
            return true;
        }
        return false;
    }

    @Override
    protected ResponseResult validateParams(BaseRequestDTO dto) {
        SfcRequestDTO sfcRequestDTO = (SfcRequestDTO) dto;
        if (sfcRequestDTO.getIsShare() == null || sfcRequestDTO.getIsShare() == 0) return ResponseResult.ERROR;
        logger.info("sfc validateParams success");
        return ResponseResult.SUCCESS;
    }

    @Override
    protected ResponseResult validateRules(BaseRequestDTO dto) {
        // 无校验
        return ResponseResult.SUCCESS;
    }

    @Override
    protected ResponseResult doProcess(BaseRequestDTO dto) {
        logger.info("sfc doProcess success");
        return ResponseResult.SUCCESS;
    }


    @Override
    protected void postProcessAction(BaseRequestDTO dto) {
        logger.info("sfc 异步执行...");
    }

}

巴士订单处理:

package strategyTest.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import strategyTest.AbstractOrderStrategy;
import strategyTest.ResponseResult;
import strategyTest.dto.BaseRequestDTO;
import strategyTest.dto.BusRequestDTO;

/**
 * 类 名 称:BusImpl
 * 类 描 述:TODO
 * 创建时间:2023/2/20 3:58 下午
 * 创 建 人:admin
 */
@Service
public class BusImpl extends AbstractOrderStrategy {
    private Logger logger = LoggerFactory.getLogger(BusImpl.class);

    @Override
    public Boolean isPracticable(BaseRequestDTO dto) {
        if (dto.getType() == 2) {
            return true;
        }
        return false;
    }

    @Override
    protected ResponseResult validateParams(BaseRequestDTO dto) {
        BusRequestDTO busRequestDTO = (BusRequestDTO) dto;
        if (busRequestDTO.getRouteId() == null || busRequestDTO.getRouteId() == 0) return ResponseResult.ERROR;
        logger.info("bus validateParams success");
        return ResponseResult.SUCCESS;
    }

    @Override
    protected ResponseResult validateRules(BaseRequestDTO dto) {
        BusRequestDTO busRequestDTO = (BusRequestDTO) dto;
        if (busRequestDTO.getSeats() != null && busRequestDTO.getSeats() > 30) return ResponseResult.ERROR;
        logger.info("bus validateRules success");
        return ResponseResult.SUCCESS;
    }

    @Override
    protected ResponseResult doProcess(BaseRequestDTO dto) {
        logger.info("bus doProcess success");
        return ResponseResult.SUCCESS;
    }


    @Override
    protected void postProcessAction(BaseRequestDTO dto) {
        logger.info("bus 异步执行...");
    }


}

3.上下文(Context)角色:持有抽象策略类的引用。(引用,执行策略)

package strategyTest;

import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import strategyTest.dto.BaseRequestDTO;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 类 名 称:StrategyContext
 * 类 描 述:策略执行上下文
 * 创建时间:2023/2/20 3:47 下午
 * 创 建 人:admin
 */
@Component
public class StrategyContext{
    // 策略管理类
    @Autowired
    private List<AbstractOrderStrategy> strategies = new ArrayList<>();

    // 获取策略类
    public AbstractOrderStrategy getStrategy(BaseRequestDTO dto) {
        for (AbstractOrderStrategy strategy : strategies) {
            if (strategy.isPracticable(dto)) {
                return strategy;
            }
        }
        return null;
    }

    
}

调用方client:

可以在一个controller,也可以写在多个controller

package strategyTest.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import strategyTest.AbstractOrderStrategy;
import strategyTest.ResponseResult;
import strategyTest.StrategyContext;
import strategyTest.dto.BaseRequestDTO;
import strategyTest.dto.BusRequestDTO;
import strategyTest.dto.SfcRequestDTO;

/**
 * 类 名 称:客户端请:可以充当controller或者业务调用上游
 * 类 描 述:TODO
 * 创建时间:2023/2/20 3:58 下午
 * 创 建 人:admin
 */
@RestController
public class ClientTest {
    @Autowired
    private StrategyContext strategyContext;

    @RequestMapping("/createSfc")
    public ResponseResult createSfc(SfcRequestDTO sfcRequestDTO){
        if(sfcRequestDTO == null){
            return ResponseResult.ERROR;
        }
        return this.createOrder(sfcRequestDTO);
    }


    @RequestMapping("/createBus")
    public ResponseResult createBus(BusRequestDTO busRequestDTO){
        if(busRequestDTO == null){
            return ResponseResult.ERROR;
        }
        return this.createOrder(busRequestDTO);
    }

    private ResponseResult createOrder(BaseRequestDTO baseRequestDTO) {
        AbstractOrderStrategy strategy = strategyContext.getStrategy(baseRequestDTO);
        if(strategy == null){
            return ResponseResult.ERROR;
        }
        return strategy.process(baseRequestDTO);
    }
}

我们看下运行结果:

sfc运行结果:

bus运行结果:

是不是非常简洁明了!!!

我们看完代码,再结合类图看下,此时如果我们想新增一种类型的创建订单流程,比如创建一笔代驾订单,需要如何做? 我们只需要做两步:

1、新增一个代驾的实现类DjImpl,继承StrategyContext类;

2、在Controller中,新增一个方法(如果不同类型的订单有不在同一个controller,可将createOrder方法抽象到父类controller,此时新增一个子类controller继承父类和父类的方法即可);

其他地方无需改动。。。其他类型的创建订单流程完全无改动,无影响。下单流程解耦,测试范围极大的降低。

想想我们在项目中,相似的场景写过多少if else。每次添加新的实现,是否影响到原有功能。结合这篇文章,希望能对读者朋友有所帮助。

总结:

策略模式帮助我们把相似的算法抽象,使用上下文管理抽象类的具体实现,每次新增算法时,只需新增具体实现。使我们的代码轻松解耦,符合开闭原则,极大的缩小了影响范围。是成为一名优秀工程师的必修课!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Spring从成神到升仙系列 一】2023年再不会动态代理,就要被淘汰了

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙…

BingGPT 国内中转

BingGPT 国内中转 本项目的github地址 本项目最上层是提供一个使用BingGPT的web接口&#xff0c;仅供学习&#xff0c;如有侵权请联系作者。 预先准备&#xff1a; 一个可以访问bingGPT的外网服务器&#xff08;可在tencent cloud 选购)一个在已经注册new_bing_list的账号 …

泰克示波器MD03012-一款高性能、高可靠性的仪器

泰克示波器MD03012是一款常见的仪器&#xff0c;以其出色的性能和高可靠性被广泛应用于电子工程、教学演示等领域。它采用先进的电子技术&#xff0c;具有高精度、高灵敏度和高可靠性等特点&#xff0c;能够满足工程师们在实际工作中的要求。泰克示波器MD03012拥有一套强大的功…

华为OD机试题,用 Java 解【数组排序】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…

Clickhouse学习(二):MergeTree存储结构

MergeTree一、MergeTree逻辑存储结构二、MergeTree物理存储结构三、总结一、MergeTree逻辑存储结构 如上图所示,在排序键(CountrID、Date)上做索引,数据会按照这两个字段先后排序ClickHouse是稀疏索引,每隔8192行做一个索引,如(a,1),(a,2),比如想查a,要读取[0,3)之间的内容,稀疏…

Python安装教程(附带安装包)

首先&#xff0c;打开python安装包的下载地址&#xff0c;https://www.python.org/downloads/&#xff0c;会有些慢 点击downloads中的windows 左侧是稳定的版本&#xff0c;我这边下的是3.8的&#xff0c;不想去官网下载的可以直接用我下载的这个3.8版本&#xff0c;https://…

隐私计算头条周刊(2.20-2.26)

开放隐私计算收录于合集#企业动态45个#周刊合辑45个#政策聚焦38个#隐私计算92个#行业研究37个开放隐私计算开放隐私计算OpenMPC是国内第一个且影响力最大的隐私计算开放社区。社区秉承开放共享的精神&#xff0c;专注于隐私计算行业的研究与布道。社区致力于隐私计算技术的传播…

Reids实战—黑马点评(三)秒杀篇

Reids实战—黑马点评&#xff08;三&#xff09;秒杀篇 来自黑马的redis课程的笔记 【黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目】 目录Reids实战—黑马点评&#xff08;三&#xff09;秒杀篇一、全局唯一I…

改进的 A*算法的路径规划(路径规划+代码+毕业设计)

引言 近年来&#xff0c;随着智能时代的到来&#xff0c;路径规划技术飞快发展&#xff0c;已经形成了一套较为成熟的理论体系。其经典规划算法包括 Dijkstra 算法、A算法、D算法、Field D算法等&#xff0c;然而传统的路径规划算法在复杂的场景的表现并不如人意&#xff0c;例…

一些cmake error fixed

建完虚拟环境后 运行 pip install . 出现报错&#xff0c;显示svox2安装出错&#xff0c;然后开始进入到svox2中进行手动编译和安装。 1. cmake svox2/csrc pybind11找不到 conda install pybind11用 pip install 在虚拟环境中安装不行&#xff0c;据说会安装到全局下… 2. c…

Allegro如何标注PCB的尺寸参数操作指导

Allegro如何标注PCB的尺寸参数操作指导 在输出生产文件之前,需要对PCB的尺寸进行标注,如下图 用Allegro如何进行标注,具体操作如下 点击Manufacture选择Dimension Enviroment<

量化学习(一)数据列表获取

试验环境 windows10 AnacondaPyCharm&#xff08;小白参考文章&#xff1a;https://coderx.com.cn/?p14&#xff09; 数据库&#xff1a; VM中安装MySQL5.7&#xff08;设置utf8及相应配置优化&#xff09; 复权 小白参考文章&#xff1a;https://zhuanlan.zhihu.com/p/469820…

实例3:树莓派呼吸灯

实例3&#xff1a;树莓派呼吸灯 实验目的 通过背景知识学习&#xff0c;了解digital与analog的区别。通过GPIO对外部LED灯进行呼吸控制&#xff0c;熟悉PWM技术。 实验要求 通过python编程&#xff0c;用GPIO控制LED灯&#xff0c;使之亮度逐渐增大&#xff0c;随后减小&am…

10万字大数据平台数据治理体系和大数据架构技术方案word

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 总体技术架构设计 基于企业内部…

高频面试题|RabbitMQ如何防止消息的重复消费?

一. 前言最近有很多小伙伴开始找工作&#xff0c;在面试时&#xff0c;面试官经常会问我们这样一个题目&#xff1a;RabbitMQ如何防止重复消费?有很多小伙伴这个时候都在想&#xff0c;消息怎么还会重复消费呢???.......所以他们在面试后就跑来问壹哥&#xff0c;针对这个比…

【华为OD机试模拟题】用 C++ 实现 - 异常的打卡记录(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明异常的打卡记录【华为OD机试模拟题】题目输入输出备注示例一输入输出说明示例二输入输出说明示例三输入输出说明

基于合作型Stackerlberg博弈的考虑差别定价和风险管理的微网运行策略研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

数据结构与算法(五):优先队列

这节总结一下优先队列的常用实现方法。 一、基本概念 普通的队列是一种先进先出的数据结构&#xff0c;元素在队列尾追加&#xff0c;而从队列头删除。在优先队列中&#xff0c;元素被赋予优先级。当访问元素时&#xff0c;具有最高优先级的元素最先删除。优先队列具有最高级…

100天精通Python(数据可视化篇)——第77天:数据可视化入门基础大全(万字总结+含常用图表动图展示)

文章目录1. 什么是数据可视化&#xff1f;2. 为什么会用数据可视化&#xff1f;3. 数据可视化的好处&#xff1f;4. 如何使用数据可视化&#xff1f;5. Python数据可视化常用工具1&#xff09;Matplotlib绘图2&#xff09;Seaborn绘图3&#xff09;Bokeh绘图6. 常用图表介绍及其…

81页5G 智慧工厂物联数字孪生可视化建设方案

数字企业建设思路3 XXXX智慧企业将以信息化为基础、以数据为纽带、以制造为核心、以管理为载体打造新型智慧园区&#xff0c;该智慧园区整合了企业的安全、环保、能源、安防、应急、服务等数据资源&#xff0c;支撑企业科学、准确、及时决策&#xff0c;提升企业综合监管能力、…