首页 > 其他分享 >策略模式

策略模式

时间:2024-03-23 15:34:23浏览次数:26  
标签:code return 策略 List 模式 public select

策略模式

了解

当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。

如果使用多重条件转移语句实现(即硬编码),不但使条件语句变得很复杂,而且增加、删除或更换算法要修改原代码,不易维护,违背开闭原则。如果采用策略模式就能很好解决该问题。

策略模式可以用来消除if…else…

应用

根据不同的场景实现不同的策略

分析

代码

实现接口注入

策略接口:

提供support方法用于检查是否支持该策略,select方法用于被重写实现不同的策略逻辑

public interface TurbinesStrategy {
    boolean support(String code);
    /**
     * 策略的对外接口,所有具体策略类都需实现该接口
     * @return
     */
    List<? extends ReuseVo> select(WindTurbinesDataDO windTurbinesDataDO);
}

具体的策略实现对应的接口:

@Component
public class SelectPower implements TurbinesStrategy {
    @Autowired
    private WindTurbinesDataMapper windTurbinesDataMapper;

    @Override
    public boolean support(String code) {
        return "turbinesPower".equals(code);
    }

    /**
     * 表示查询功率的具体策略,这是第一种策略
     *
     * @return
     */
    @Override
    public List<TurbinesPower> select(WindTurbinesDataDO windTurbinesDataDO) {
        return windTurbinesDataMapper.selectTurbinesPowerList(windTurbinesDataDO);
    }
}
@Component
public class SelectTurbinesSpeed implements TurbinesStrategy {
    @Autowired
    private WindTurbinesDataMapper windTurbinesDataMapper;

    @Override
    public boolean support(String code) {
        return "TurbinesSpeed".equals(code);
    }

    @Override// 第二种策略
    public List<TurbinesSpeed> select(WindTurbinesDataDO windTurbinesDataDO) {
        return windTurbinesDataMapper.selectTurbinesSpeedList(windTurbinesDataDO);
    }
}

具体使用:

@RestController
@RequestMapping("/windTurbines")
public class WindTurbinesDataController extends BaseController implements ApplicationContextAware, InitializingBean {

    private List<TurbinesStrategy> strategieList = new ArrayList<>();
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;// 将Spring容器注入进来,需要实现ApplicationContextAware接口
    }

    @Override
    public void afterPropertiesSet() {// 实现InitializingBean接口,根据bean类型拿到BeanMap,转为list
        Map<String, TurbinesStrategy> beansOfType = context.getBeansOfType(TurbinesStrategy.class);
        System.out.println(beansOfType);
        beansOfType.forEach((key,value)->strategieList.add(value));
    }

    /**
     * 查询风电机组列表
     */
    @PreAuthorize("@ss.hasPermi('dataManagement:windTurbines:list')")
    @GetMapping("/list")
    public TableDataInfo list(WindTurbinesDataDO windTurbinesDataDO)
    {
        String code = windTurbinesDataDO.getCode();// 根据前端传递的code码调用相应的策略
        List<? extends ReuseVo> select = null;
        for (TurbinesStrategy turbinesStrategy : strategieList) {// 遍历策略list找到该策略,然后调用实现
            if (turbinesStrategy.support(code)){
                select = turbinesStrategy.select(windTurbinesDataDO);
            }
        }
        return getDataTable(select);
    }
}

这里其实还可以直接使用@Autowired直接将策略bean注入进来,而不必要实现接口再拿,这样support接口也可以省略。

在使用@Component将策略注入Spring容器的时候,指定存入容器bean的名字(不指定默认为该类的类名首字母小写),在使用时直接使用@Autowired注解注入map或者list,

map可以直接get,list仍需要遍历寻找。

如果不指定注入bean的名字,需要前端传递的code码与策略类名首字母小写对应,指定bean名可以传递一般化的参数,与指定的名字对应即可。

使用@Autowired注入

@RestController
@RequestMapping("/windTurbines")
public class WindTurbinesDataController extends BaseController {

    @Autowired
    private Map<String, TurbinesStrategy> strategieMap = new HashMap<>();

    /**
     * 查询风电机组列表
     */
    @PreAuthorize("@ss.hasPermi('dataManagement:windTurbines:list')")
    @GetMapping("/list")
    public TableDataInfo list(WindTurbinesDataDO windTurbinesDataDO) {
        String code = windTurbinesDataDO.getCode();
        List<? extends ReuseVo> select = null;
        TurbinesStrategy turbinesStrategy = strategieMap.get(code);
        select = turbinesStrategy.select(windTurbinesDataDO);
        return getDataTable(select);
    }
}

使用map效果图:key为我指定的bean名,value是我注入的类(具体的策略实现)

image

效果

  1. 减少了前端接口调用次数
  2. 避免了查重复的数据,减少了不必要的数据查询,减少了后端接口的数量
  3. 减轻数据库压力提高效率
  4. 并且复用接口,提高了可扩展性

扩展

策略如果没有找到呢?如何实现默认策略?由于我上面的业务不需要用到默认策略实现,所以在这里进行扩展。

抽象策略(Strategy)类
具体策略(Concrete Strategy)类
环境(Context)类

使用策略模式的第三个角色—环境(Context)类,上面的例子只使用到前两个角色,那么使用第三个角色的策略模式怎么实现呢?

额。。。其实控制层就是环境类,策略对象(本身/map/List)是它的成员变量

那么:

还可以使用枚举去实现具体的策略,这样做可以使用一个文件即做到实现不同的策略

public enum StrategyEnum {
    A {
        @Override
        public List<? extends ReuseVo> select(WindMeasurementTowerDataDO windMeasurementTowerDataDO) {
            return null;
        }
    },
    B {
        @Override
        public List<? extends ReuseVo> select(WindMeasurementTowerDataDO windMeasurementTowerDataDO) {
            return null;
        }
    };

    List<? extends ReuseVo> select(WindMeasurementTowerDataDO windMeasurementTowerDataDO) {
        return null;
    }

}

牵扯出另一个问题:

[怎么往枚举类里注入Bean](# 怎么往枚举类里注入Bean)

使用枚举类使用效果成功,枚举类的valueof()方法通过前端的code码获得对应的枚举类型,执行被重写的具体策略。

image

存疑

mapper接口能使用泛型协变逆变吗???如何实现

List<? extends ReuseVo> selectWindMeasurementTowerDataListReuse(WindMeasurementTowerDataDO windMeasurementTowerDataDO);

怎么往枚举类里注入Bean

如果在枚举类上加@Component注解会导致如下报错:

Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException

可以得知枚举类是无法直接交给Spring容器管理的。

究其原因,是因为Spring没有找到构造方法,那么我给枚举添加构造方法之后会怎么样呢?

还是创建Bean失败,不能找到构造方法,因为枚举类的构造方法不是public的,并且也不能用public修饰。

解决:

使用内部类的方式,借由内部类暴露所需要的组件

public enum StrategyEnum {
    A {
        @Override
        public List<? extends ReuseVo> select(WindMeasurementTowerDataDO windMeasurementTowerDataDO) {
            return MyBeanAContainer.getMyBeanA().selectWindMeasurementTowerDataSpeedList(windMeasurementTowerDataDO);
        }
    },
    B {
        @Override
        public List<? extends ReuseVo> select(WindMeasurementTowerDataDO windMeasurementTowerDataDO) {
            return MyBeanAContainer.getMyBeanA().selectWindMeasurementTowerDataSurfacePressureList(windMeasurementTowerDataDO);
        }
    };


    public abstract List<? extends ReuseVo> select(WindMeasurementTowerDataDO windMeasurementTowerDataDO);
    @PostConstruct
    public void init(){

    }

    @Component
    static class MyBeanAContainer {

        @Autowired
        WindMeasurementTowerDataMapper windMeasurementTowerDataMapper;
        private static WindMeasurementTowerDataMapper mapper;

        @PostConstruct// 静态属性无法直接注入,我们借由 @PostConstruct 初始化回调为它赋值,该回调方法在所有 bean 注册完成后,因此没有问题 
        public void init() {// 该方法也是解决 静态属性注入 最常用的方法
            mapper = windMeasurementTowerDataMapper;
        }

        static WindMeasurementTowerDataMapper getMyBeanA() {
            return mapper;
        }
    }
}

标签:code,return,策略,List,模式,public,select
From: https://www.cnblogs.com/code-jia/p/18091164

相关文章

  • mongoDB使用记录:副本集选举淘汰策略失效
    一个问题场景:业务请求查询数据库,当请求没有成功返回时(这里是数据库机器异常,表现是不返回请求结果,处于假死状态),业务挂起进入等待(WAIT),逻辑中断,表现为卡顿、持续加载中;高并发场景下,短时间内堆积的请求会大量占用发起数据库请求的机器的内存(风险一),大量业务卡顿异常;当数据库异常解决成......
  • 套不了模式,又怕被雷劈
    Lynn2024-3-1820:25潘老师,要是现状很烂怎么套改进模式?我现在碰到的问题有点像您需求启发那一章的例子。书上写操作工干活时手写记录,可是我调研到的现状是基本上连手写记录都没有。画现状的时候应该怎样画呢?如果什么都不画,感觉套不上改进模式,如果改成手写记录则不真实,按照......
  • AI大模型与碳足迹评估结合模式及示范案例
            AI大模型与碳足迹评估相结合,可以提供更精确、更快速的碳排放量计算,优化减排策略,并促进可持续发展目标的实现。1.背景与挑战        企业和组织面临日益增加的压力,要求他们减少运营的环境影响,尤其是减少温室气体排放。传统的碳足迹评估方法往往耗时长......
  • 产业园区开发运营及盈利模式分析
    摘要:产业园区一般由政府或企业开发建设,是区域经济和产业发展的重要空间载体,具有显著的资源集聚能力和产业规模效益,承担着产业要素集聚、新型产业培育、经济高质量发展和新型城镇化建设等重要使命。然而,当前国内部分产业园区因前期开发投入规模大、后期招商及运营管理模式不健全,导......
  • 01-Spark的Local模式与应用开发入门
    1Spark的local模式Spark运行模式之一,用于在本地机器上单机模拟分布式计算的环境。在local模式下,Spark会使用单个JVM进程来模拟分布式集群行为,所有Spark组件(如SparkContext、Executor等)都运行在同一个JVM进程中,不涉及集群间通信,适用本地开发、测试和调试。1.1重......
  • Windows中控制台(cmd)模式下运行程序卡死/挂起现象解决方案(快速编辑模式)
    最近在运行编译好的exe文件时,发现了一个现象,就是通过cmd运行exe文件或者双击执行运行exe文件,偶尔会出现程序没有执行的情况。最开始发现这个现象时,还以为是程序出现了什么Bug。后面经过网上查询才知道,原始这一切都是控制台(cmd)模式下快速编辑模式捣的鬼。可能大家平常没有接触到,......
  • 数据泄密的危害,原因,与应对策略
    在当今信息化的时代,数据安全问题尤为重要。数以千计的公司遭受了数据泄露的威胁,这不仅会造成公司固有资产的损失,也可能影响到公司的声誉和业务运作。数据泄露的原因复杂,而途径则多种多样,我们需要认真分析,并采取科学的防护措施。数据泄密的危害2017年全球数据泄露事件频发,从IBM......
  • 【转】[C#] 单例模式
    来自:阿里的通义灵码在C#中,单例模式实现线程安全时通常会采用双重检查锁定(Double-CheckedLocking,DCL)的策略来确保只创建类的一个实例,并且这个过程是线程安全的。两层lock的设计是为了减少获取锁的开销,尤其是当类的实例已经被初始化的情况下。以下是一个使用双重检查锁定的C#......
  • 揭密网络犯罪商业模式及其价值链
    基于网络的犯罪活动越来越多,网络犯罪已经形成了一套庞大商业模式,网络犯罪即服务,通过购买服务可以从事各种网络犯罪活动,也正是因为这种商业模式的出现,导致网络犯罪成本越来越低,实施网络犯罪的团伙也在不断增加,基于这种商业模式,任何人都可以通过地址网络犯罪组织购买相应的服务,从......
  • Linux 多网卡做bond模式
    bond概念将两张网卡绑定,共用一个IP,实现冗余效果。实际上Linux双网卡的绑定模式有7种,而在这里常用的是active-backup,一个设备如果只有一个网卡,那么当这个网卡损坏时设备的网络就会瘫痪。绑定接口的作用就是让多个物理网卡服务于一个IP地址,使得这个网络的抵抗性强。一个设备只......