首页 > 其他分享 >利用策略模式结合Springboot框架

利用策略模式结合Springboot框架

时间:2023-07-25 17:03:32浏览次数:51  
标签:return Springboot 框架 模式 mbDimension 维度 questionBankId children dimensions

利用策略模式解决多条件问题

问题重现

这是公司代码里面的一个接口,我需要根据type的不同,去决定要不要存储里面的对象。

ini复制代码 @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveDimensionsByQuestionBankId(List<MbDimensionsDto> dimensions, Long questionBankId,Integer type) {
        //如果是无维度,说明不用保存
        if(type == QuestionBankSettingTypeEnum.无维度.getValue()){
            return true;
        }
        //如果不是,就先检验
        checkIsDimensionsDtoLegal(dimensions);


        if(type.equals(QuestionBankSettingTypeEnum.一极维度.getValue())){
            dimensions.forEach(mbDimensionDto -> {
                MbDimension mbDimension = new MbDimension();
                BeanUtils.copyProperties(mbDimensionDto, mbDimension);
                mbDimension.setQuestionBankId(questionBankId);
                this.save(mbDimension);
            });
            return true;
        }

        if(type.equals(QuestionBankSettingTypeEnum.二级维度.getValue())){
            //新增树状dimensions
            dimensions.forEach(mbDimensionDto -> {
                MbDimension mbDimension = new MbDimension();
                BeanUtils.copyProperties(mbDimensionDto, mbDimension);
                mbDimension.setQuestionBankId(questionBankId);
                this.save(mbDimension);
                Long fatherId = mbDimension.getId();
                List<MbDimensionsDto> children = mbDimensionDto.getChildren();

                if(children == null){
                    return;
                }
                children.forEach(son -> {
                    MbDimension mbDimensionSon = new MbDimension();
                    BeanUtils.copyProperties(son, mbDimensionSon);
                    mbDimensionSon.setQuestionBankId(questionBankId);
                    //新增后的dimension的id,即为chidren dimension的父亲id.
                    mbDimensionSon.setParentId(fatherId);
                    this.save(mbDimensionSon);
                });
            });
            return true;
        }
        return false;
    }

不得不说,相当的丑陋!!

有一个学长的话在我脑子中不断回响:“写代码就得优雅!!”

于是我重拾起他说了很多次的策略模式。

实战

定义策略接口和实现类

对于保存维度这个方法,我们不妨给他设置一个接口。

php复制代码/**
 * @author ht
 */
public interface SaveDimensionStrategy {
    /**
     * 当前的维度模式,是无维度还是一级维度,还是二级维度
     * @return
     */
    Integer getType();

    /**
     * 根据当前维度,进行处理
     * @param dimensions
     * @param questionBankId
     * @return
     */
    boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId);
}

我们目前有三个类,都需要实现这个接口,来进行不同的行为,在这里就是对维度的不同操作。

无维度

由于无维度无需处理,直接返回true即可

typescript复制代码@Component
public class SaveNoDimensionStrategy implements SaveDimensionStrategy {

    @Override
    public Integer getType() {
        return QuestionBankSettingTypeEnum.无维度.getValue();
    }

    @Override
    public boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId) {
        return true;
    }
}

一级维度

typescript复制代码@Component
public class SaveOneDimensionStrategy implements SaveDimensionStrategy {

    @Resource
    private MbDimensionService mbDimensionService;

    @Override
    public Integer getType() {
        return QuestionBankSettingTypeEnum.一极维度.getValue();
    }

    @Override
    public boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId) {

        checkIsDimensionsDtoLegal(dimensions);
        //批量添加
        dimensions.forEach(mbDimensionDto -> {
            MbDimension mbDimension = new MbDimension();
            BeanUtils.copyProperties(mbDimensionDto, mbDimension);
            mbDimension.setQuestionBankId(questionBankId);
            mbDimensionService.save(mbDimension);
        });

        return true;
    }


    private void checkIsDimensionsDtoLegal(List<MbDimensionsDto> dimensions) {

        dimensions.forEach(dimension -> {
            if (StringUtils.isEmpty(dimension.getName())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            if (dimension.getWeight() < 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            List<MbDimensionsDto> children = dimension.getChildren();
            if (children != null && children.size() != 0) {
                //递归校验
                checkIsDimensionsDtoLegal(children);
            }
        });
    }
}

二级维度

scss复制代码@Component
public class SaveTwoDimensionStrategy implements SaveDimensionStrategy {


    @Resource
    private MbDimensionService mbDimensionService;

    @Override
    public Integer getType() {
        return QuestionBankSettingTypeEnum.二级维度.getValue();
    }

    @Override
    public boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId) {
        checkIsDimensionsDtoLegal(dimensions);
        //新增树状dimensions
        dimensions.forEach(mbDimensionDto -> {
            MbDimension mbDimension = new MbDimension();
            BeanUtils.copyProperties(mbDimensionDto, mbDimension);
            mbDimension.setQuestionBankId(questionBankId);
            mbDimensionService.save(mbDimension);
            Long fatherId = mbDimension.getId();
            List<MbDimensionsDto> children = mbDimensionDto.getChildren();

            if(children == null){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"二级维度中,父维度一定要有子维度");
            }

            children.forEach(son -> {
                MbDimension mbDimensionSon = new MbDimension();
                BeanUtils.copyProperties(son, mbDimensionSon);
                mbDimensionSon.setQuestionBankId(questionBankId);
                //新增后的dimension的id,即为chidren dimension的父亲id.
                mbDimensionSon.setParentId(fatherId);
                mbDimensionService.save(mbDimensionSon);
            });
        });
        return true;
    }


    private void checkIsDimensionsDtoLegal(List<MbDimensionsDto> dimensions) {
        dimensions.forEach(dimension -> {
            if (StringUtils.isEmpty(dimension.getName())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            if (dimension.getWeight() < 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            List<MbDimensionsDto> children = dimension.getChildren();
            if (children != null && children.size() != 0) {
                //递归校验
                checkIsDimensionsDtoLegal(children);
            }
        });
    }
}

由此可见,我们做的不过是把行为抽象成了接口,利用三个实现类去规范不同的行为。

这里实现类都加上了@Component注解,让它变成一个个Bean,同时Spring去管理。

定义Map和runner

现在已经有了一系列解决方案,也就是我们写的一个个实现类。现在我们需要一个容器去把这一个个的解决方案跑起来!

见名知义,runner就是为此而生的。

我们定义一个
SaveDimensionStrategyRunner

java复制代码@Component
public interface SaveDimensionStrategyRunner {
    /**
     * 根据 type 字段执行不同策略
     * @return
     */
    boolean saveDimension(List<MbDimensionsDto> dimensionsDtos, Long questionBankId,Integer type);
}

接下来,我们定义实现类。

typescript复制代码/**
 * 用来管理策略模式使用的bean,放入map进行管理
 */
@Configuration
public class StrategyConfig {

    @Bean
    public SaveDimensionStrategyRunner strategyRunner(List<SaveDimensionStrategy> strategies) {
        Map<Integer, SaveDimensionStrategy> strategyMap = strategies.stream()
                .collect(Collectors.toMap(SaveDimensionStrategy::getType, s -> s));
        return (dimensionsDtoList,questionBankId,type) -> strategyMap.get(type).saveDimensionStrategy(dimensionsDtoList,questionBankId);
    }

}

这段代码做了几件事情:

  1. 由于之前定义的strategy被打上了@Component注解,因此,他们会被spring管理,注入到这个方法的参数里。
  2. 根据传入的各个strategy,我们将他们的type设置为key,本身设置为value,放入map集合中。
  3. return语句中是 对SaveDimensionStrategyRunner这个接口中的方法的实现,也就是说,我们返回的就是刚刚定义的接口的实现类,又由于加上了@Bean注解,该实例会被spring所管理。

使用

我们在需要这个方法的实现类中注入runner

java复制代码    @Resource
    private SaveDimensionStrategyRunner saveDimensionStrategyRunner;

然后直接调用它的方法就可以啦!

标签:return,Springboot,框架,模式,mbDimension,维度,questionBankId,children,dimensions
From: https://blog.51cto.com/u_16173760/6846961

相关文章

  • 设计模式-职责链模式在Java中使用示例-采购审批系统
    场景采购单分级审批采购审批是分级进行的,即根据采购金额的不同由不同层次的主管人员来审批,主任可以审批5万元以下(不包括5万元)的采购单,副董事长可以审批5万元至10万元(不包括10万元)的采购单,董事长可以审批10万元至50万元(不包括50万元)的采购单,50万元及以上的采购单就需要开董事会......
  • 纯手撸 Django web框架批量删除redis的key
    纯手撸Djangoweb框架批量删除redis的key环境环境参照上一章节博客部署环境,在此基础上进行功能加强【批量删除指定前缀的key】,然后再CI里面掉这个接口地址即可清理redis缓存的key,更加高效的运维工作修改视图##mysite/myweb1/views.py#Createyourviewshere.fromdj......
  • springboot学习之十五(Spring Security-记住我Remember me)
     一.记住我概述1.1.什么是记住我Rememberme(记住我)记住我,当用户发起登录勾选了记住我,在一定的时间内再次登录就不用输入用户名和密码了,即使浏览器退出重新打开也是如此。1.2.流程分析在SpringSecurity中提供RememberMeAuthenticationFilter过滤器来实现记住我功能,其核心流......
  • .NET(C#) 设计模式
    .NET(C#)设计模式简介设计模式(Designpattern)是代码设计经验的总结。设计模式主要分三个类型:创建型、结构型和行为型。创建型是对象实例化的模式,创建型模式用于解耦对象的实例化过程,主要用于创建对象。结构型是把类或对象结合在一起形成一个更大的结构,主要用于优化不同类、对......
  • Solon 框架,单月下载量突破 200 万了!
    Solon是什么开源项目?一个,Java新的生态型应用开发框架。它从零开始构建,有自己的标准规范与开放生态(历时五年,已有全球第二级别的生态规模)。与其他框架相比,它解决了两个重要的痛点:启动慢,费内存。关键记事:2021年1月,正式对外开源2022年7月,建立官网,发力推广2023年2月,v2.0发布......
  • 设计模式—享元模式
    享元模式享元模式(FlyweightPattern)是池技术的重要实现方式,其定义如下:Usesharingtosupportlargenumbersoffine-grainedobjectsefficiently.(使用共享对象可有效地支持大量的细粒度的对象。)优点与缺点享元模式是一个非常简单的模式,它可以大大减少应用程序创建的对象,降......
  • 设计模式—组合模式
    组合模式目录组合模式优点缺点使用场景注意事项例子组合模式(CompositePattern)也叫合成模式,有时又叫做部分-整体模式(Part-Whole),主要是用来描述部分与整体的关系。将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。优点......
  • 设计模式—状态模式
    状态模式目录状态模式优点缺点适用场景注意事项通用类图例子状态模式与策略模式的差异当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。优点结构清......
  • 设计模式—中介者模式
    中介者模式目录中介者模式优点缺点适用场景中介者模式与外观模式差异用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。优点减少类之间的依赖,将原有的一对多的依赖变成一对一的依赖,同事类只依赖中......
  • 设计模式—单例模式
    目录优点缺点使用场景注意事项案例分析定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。优点由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。由......