专栏首页关忆北.基于SpringBoot的策略模式demo

基于SpringBoot的策略模式demo

策略模式

策略模式是Java 23种设计模式之一,在https://refactoring.guru/design-patterns/网站中这样对策略模式进行了解释:

Strategy is a behavioral design pattern that turns a set of behaviors into objects and makes them interchangeable inside original context object.

白话翻译一下就是:策略模式可以根据上下文对象的不同状态去执行不同的逻辑(策略实现)。最简单使用场景是:当代码中出现了三重以上的if else判断,这时代码的可读性会非常差,这时可以使用到策略模式去拯救if else.当然也可以使用switch,但是相较于策略模式,switch的代码清晰度还是差了些。

策略模式不同角色

  1. Strategy:抽象策略角色,对算法、策略的抽象,定义每个算法、策略所必需的方法,通常为接口。
  2. ConcreteStrategy:具体策略角色,实现抽象策略角色,完成具体的算法、策略。
  3. Context:上下文环境角色,保存了ConcreteStrategy,负责调用ConcreteStrategy。

SpringBoot下使用策略模式

加减乘除的计算器如果使用传统的if else的话,至少需要写三次if和一次else,如果使用switch的话,则在一个方法中堆叠四个case或者三个case一个default,如果每个if条件下的逻辑都特别多的话,代码会显得特别臃肿,在《阿里巴巴开发手册》中规定:一个方法中代码量不能超过80行,如果逻辑判断都挤在一个方法里,代码量一定会超过80行,ok,你的KPI完了。所以,年轻人,耗子尾汁,还不赶紧学学策略模式。

接下来我将使用加减乘除的一个小案例来写一个最简单的策略模式的demo

  • 0、引入pom
       <!-- SpringBoot所必须的依赖-->
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
    
    <!-- demo中使用guava的Maps集合和判空-->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>29.0-jre</version>
        </dependency>

建议:新建一个strategy包,包下定义策略接口实现包strategyImpl和不同的策略角色,也就是上文中的2 ps:实际项目中传参可能不是基本类型,而是一个自定义的一个包装类型(实体类),所以入参判断可以使用@Validated注解判空,我这里是int基本类型,所以在判空的时候就使用了Google guava封装的Preconditions去判空,业务判空一定要提前,不要走到较深的业务中再去判空

1、定义策略接口,也就是上文中的1

CalculationStrategy.java

/**
 * @author Liu-PC
 */
public interface CalculationStrategy {
    /**
     * 策略模式的策略接口定义
     * @param num1 first
     * @param num2 second
     * @return
     */
    int operate(int num1, int num2);

}

AddCalculationStrategyImpl.java

/**
 * @author Liutx
 * @date 2020/11/28 16:05
 * @Description
 */
@Component("add")
public class AddCalculationStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 + num2;
    }
}

这里的@Component是把当前策略的实现类注册为一个组件,交由Spring管理。add是策略的名字,策略的名字不能重复,因为我们策略接口通过组件的名字来找到具体的策略角色。

DivisionStrategyImpl.java

/**
 * @author Liutx
 * @date 2020/11/28 16:18
 * @Description
 */
 @Component("Division")
public class DivisionStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 / num2;
    }
}

MultiplicationStrategyImpl.java

@Component("multiple")
public class MultiplicationStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 * num2;
    }
}

SubtractionStrategyImpl.java

@Component("subtract")
public class SubtractionStrategyImpl implements CalculationStrategy {

    @Override
    public int operate(int num1, int num2) {
        return num1 - num2;
    }
}
  • 3、创建上下文对象去调用策略

CalculationContext.java

/**
 * @author Liutx
 * @date 2020/11/28 16:23
 * @Description 策略上下文类,把传入的参数放到map中,作为策略接口的入参
 */

@Component
@Getter
public class CalculationContext {
    /**
     *  把策略角色(类型)key,和参数value放到Map中
     *  key就是beanName(具体策略实现类中@Component的名字),value就是接口(具体的实现类)
     *  Maps是guava下的封装类型,实则是静态的创建了一个HashMap的对象,Maps可以根据key去获取value对象
     */

    public final Map<String, CalculationStrategy> calculationStrategyMap = Maps.newHashMapWithExpectedSize(4);

    public CalculationContext(Map<String, CalculationStrategy> calculationStrategyMap) {
        this.calculationStrategyMap.clear();
        this.calculationStrategyMap.putAll(calculationStrategyMap);
    }
    
    
    //可以使用@Getter注解代替,这样写方便读者理解在Service层调用Context执行策略
    public Map<String, CalculationStrategy> getCalculationStrategyMap() {
        return calculationStrategyMap;
    }
}

同样需要使用@Component,个人理解策略模式中的Context对象实例就像是一个执行者

以上,策略模式就已经写完了,下面是Controller中调用Service,Service中的Context"执行者"通过@Autowired注入的方式去获得Context对象,对象根据不同的策略角色去执行不同的策略实现。

CalculationService.java

/**
 * @author Liutx
 * @date 2020/11/28 16:03
 * @Description Service里执行,相当于写在ServiceImpl里的业务逻辑,可以在Controller里调用
 * 上下文环境角色,保存了ConcreteStrategy,负责调用ConcreteStrategy,所以就使用Context对象去执行策略
 * 策略的不同实现类,就相当于if else中不同的逻辑代码
 * 本demo使用加减乘除代替不同的策略逻辑
 */

@Service
public class CalculationService {

    @Autowired
    private CalculationContext calculationContext;

    public int operateByStrategy(String strategy, int num1, int num2) {
        //获取入参,根据不同的参数类型去执行不同的策略,Context的get方法是在这个地方用到的,operate方法就是一开始定义的策略接口
        return calculationContext.getCalculationStrategyMap().get(strategy).operate(num1, num2);
    }
}

TestController.class

@RestController
@RequestMapping("/test")
public class TestController {
    @Autowired
    private CalculationService calculationService;

    @GetMapping("calculation")
    public int testCalculation(String operation, int num1, int num2) {
        //省略参数判空
        return condition = calculationService.operateByStrategy(operation, num1, num2);
    }
}

Postman测试

1-1=0

over ~ ~ ~

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!
本文分享自作者个人站点/博客:https://blog.csdn.net/weixin_42313773复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • RabbitMQ入门Demo,基于springboot

    前面几章我们基本了解了RabbitMQ的基本概念,以及RabbitMQ是如何保证消息的可靠性的,那么本章开始,将真正用java代码去连接使用一些RabbitMQ...

    诺浅
  • SpringBoot使用策略模式+工厂模式

    为了防止大量的if...else...或switch case代码的出现,可以使用策略模式+工厂模式进行优化。 在我的项目当中,报表繁多,所以尝试了这种方式进...

    Johnson木木
  • Springboot中实现策略模式+工厂模式

    策略模式和工厂模式相信大家都比较熟悉,但是大家有没有在springboot中实现策略和工厂模式?

    肉眼品世界
  • SpringBoot结合策略模式实战套路

    我们都知道设计模式好,可以让我们的代码更具可读性,扩展性,易于维护,但大部分程序猿一开始都学过至少一遍设计模式吧,实战中不知用到了几成。接下来让我介绍一个结合S...

    老梁
  • 基于策略模式实现对渠道的路由

    首先将需要路由的渠道信息采用map进行封装,这样的话,可以在使用的时候基于特定的策略进行路由。

    路行的亚洲
  • SpringBoot整合redis的demo

    前面已经写过redis的安装教程,所以前期的安装方面的问题也就直接省略掉,由于对redis这部分内容掌握较差,在验证的过程中也遇到了很多问题,先记录后面再继续验...

    在水一方
  • SpringBoot下的策略模式,消灭了大量的ifelse,真香!

    项目中有这样一个场景,在公园放置了用来拍摄人像的识别杆,根据用户在不同识别杆之间采集的图象来计算用户的运动距离。由于涉及到许多公园,每个公园的布局不同,识别杆之...

    程序新视界
  • java中的策略模式(策略模式java)

    当代码中出现多重if-else语句或者switch语句时。弊端之一:如果这样的代码出现在多处,那么一旦出现需求变更,就需要把所有地方的if-else或者swit...

    全栈程序员站长
  • Java策略模式设计(简易收银台SpringBoot)

    cwl_java
  • 基于【策略模式】设计多渠道发送消息

    黎明大大
  • 设计模式--策略模式的思考

    策略模式是一种简单的设计模式,但是其在业务开发中是一种非常有用的设计模式.举个例子,当你的业务需要针对不同的场景(可以简单理解为枚举类),执行不同的策略时那么使...

    屈定
  • springboot-mybatis-demo遇到的坑

    使用国外站点进行更新,实在太浪费时间,所以修改为国内站点 在pom.xml中添加(pom.xml集成了依赖关系)

    Enterprise_
  • springboot-mybatis-demo遇到的坑

    使用国外站点进行更新,实在太浪费时间,所以修改为国内站点 在pom.xml中添加(pom.xml集成了依赖关系)

    Enterprise_
  • 前端的设计模式系列-策略模式

    代码也写了几年了,设计模式处于看了忘,忘了看的状态,最近对设计模式有了点感觉,索性就再学习总结下吧。

    windliang
  • 【设计模式】汉堡中的设计模式——策略模式

    话说昨天,麦当劳搞活动,板烧只要5块大洋!!!下班了之后我就骑着心爱的小摩托飞奔过去,在等待了一段(long)时(long)间(time)...... 终于如愿...

    落寞的鱼丶
  • 基于DOCKER安装Redis Sentinel 集群以及springboot连接Redis哨兵集群demo

    yingzi_code
  • 策略模式一 简介二 策略模式的结构三 lambda实例

    JavaEdge

扫码关注腾讯云开发者

领取腾讯云代金券