ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

06-10-设计模式 策略模式

2022-05-27 19:32:22  阅读:158  来源: 互联网

标签:10 06 String pageSize Long key pageNum 设计模式 public


策略模式

基本介绍

1)策略模式(StrategyPattern)中,定义算法族(策略组),分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户

2)这算法体现了几个设计原则,第一、把变化的代码从不变的代码中分离出来;第二、针对接口编程而不是具体类(定义了策略接口);第三、多用组合/聚合,少用继承(客户通过组合方式使用策略)。

说明:从上图可以看到,客户context有成员变量strategy或者其他的策略接口,至于需要使用到哪个策略,我们可以在构造器中指定

策略模式优化IF else

类图

使用策略模式+工厂+模板方法 解决多分类查询

  1. 浏览器调用Controller, Controller调用Service, Service调用查询工厂
  2. 在WarningQueryFactory中维护查询Key和具体查询的的关系, 并实现ApplicationContextAware接口获取到IOC, 然后通过IOC获取抽象查询类调用(AbstractWarningQuery, 并调用抽象查询类的模板方法
  3. 在WaringQuery接口中定义统一查询方法
  4. 使用AbstractWaringQuery对其进行实现, 并在其中定义模板方法, 并且在模板方法中调用抽象接口
  5. 具体查询实现类继承抽象查询类, 并实现WarningQuery接口中的查询方法, 同时注册到IOC中, 可以让工厂从IOC中获取到

这是一个标准的策略+模板的实现. 本来我想在其中加入状态模式, 用于控制是根据一些参数, 来决定查询DB还是查询缓存, 但是后来应为一些场景是缓存实现不了的, 只能查DB了, 但是一些公用数据还是查询缓存的, 后续如果需要扩展其他查询, 只需要在工厂层中维护映射关系, 并添加新的实现类继承抽象查询类(AbstractWariningQuery), 并实现WarningQuery接口的查询方法即可

代码实现

Controller层

@GetMapping("/queryWarningByKeyPage")
public Object queryWarningByKey(@Valid WarningQueryParam warningQueryParam) {
    return warningService.queryWarningByKey(warningQueryParam);
}

Service层

/**
* 根据配置决定查询数据库还是缓存默认为数据库,缓存还有问题(2022/5/12 已修复)
*
* @param warningQueryParam 预警查询条件
* @return 数据
*/
public Object queryWarningByKey(WarningQueryParam warningQueryParam) {
    String key = warningQueryParam.getKey();
    String deptName = warningQueryParam.getDeptName();
    Long pageNum = warningQueryParam.getPageNum();
    Long pageSize = warningQueryParam.getPageSize();
    return warningQueryFactory.queryDataByKey(key, deptName, pageNum, pageSize);
}

工厂

@Component
public class WarningQueryFactory implements ApplicationContextAware {

    public static final ConcurrentHashMap<String, String> context = new ConcurrentHashMap<>();

    private ApplicationContext applicationContext;

    static {
//        context.put("021","opwWarningQuery");
        context.put("022","opwWarningQuery");
        String videoWarning = "videoWarningQuery";
        context.put("011",videoWarning);
    }

    public Object queryDataByKey(String key,String deptName,Long pageNum, Long pageSize){
        if("021".equals(key)){
            throw new BusinessException("该类型接口暂未实现, 敬请期待!");
        }
        String s = context.get(key);
        AbstractWaringQuery bean = applicationContext.getBean(s, AbstractWaringQuery.class);
        return bean.queryWarningByKeyPageBase(key,deptName,pageNum,pageSize);
    }

    @Override
    public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

高层查询接口

public interface WaringQuery {
    Object queryWaringByKeyPage(String key,String deptName, Long pageNum, Long pageSize);
}

抽象实现者

public abstract class AbstractWaringQuery implements WaringQuery {

    public Object queryWarningByKeyPageBase(String key,String deptName,Long pageNum, Long pageSize){
        if(pageNum == null || pageNum < 1){
            pageNum = 1L;
        }
        if(pageSize == null || pageSize < 1){
            pageSize = 4L;
        }
        return queryWaringByKeyPage(key,deptName,pageNum,pageSize);
    }
}

具体实现者OPW

@Component
public class OpwWarningQuery extends AbstractWaringQuery {
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private DeptService deptService;

    @Autowired
    private PressureService pressureService;

    @Value("${query.warning.type}")
    private String queryType;

    @Autowired
    private UserContextService userContextService;

    @Autowired
    private OnlineService onlineService;

    @Override
    public CommonPage<List<PressureVo>> queryWaringByKeyPage(String key, String deptName, Long pageNum, Long pageSize) {
        // 暂时不支持Redis了
//        if (QueryType.REDIS.equals(queryType)) {
//            return queryDataByRedis(key, pageNum, pageSize);
//        }
        return queryDateByDb(key,deptName, pageNum, pageSize);
    }

    private CommonPage<List<PressureVo>> queryDateByDb(String key,String deptName, Long pageNum, Long pageSize) {
        // 业务逻辑
    }

    private CommonPage<List<PressureVo>> queryDataByRedis(String key, Long pageNum, Long pageSize) {
        // 业务逻辑
    }

    private List<PressureVo> addIsOnline(List<Pressure> records, List<String> deptCodes) {
        // 业务逻辑
    }
}

策略模式的注意事项和细节

1)策略模式的关键是:分析项目中变化部分与不变部分

2)策略模式的核心思想是:多用组合/聚合少用继承;用行为类组合,而不是行为的继承。更有弹性

3)体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一种策略(或者行为)即可,避免了使用多重转移语句(if..elseif..else)

4)提供了可以替换继承关系的办法:策略模式将算法封装在独立的Strategy类中使得你可以独立于其Context改变它,使它易于切换、易于理解、易于扩展

5)需要注意的是:每添加一个策略就要增加一个类,当策略过多是会导致类数目庞

标签:10,06,String,pageSize,Long,key,pageNum,设计模式,public
来源: https://www.cnblogs.com/flower-dance/p/16318896.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有