zoukankan      html  css  js  c++  java
  • 策略模式+元注解方式替代大量if else写法

    1、策略模式简介

    设计模式的知识可以参考我的设计模式笔记专栏:设计模式系列博客

    策略模式:定义一系列算法,然后将每一个算法封装起来,并将它们可以互相替换。也就是将一系列算法封装到一系列策略类里面。策略模式是一种对象行为型模式。策略模式符合“开闭原则“

    Strategy Pattern: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

    策略模式包括如下角色:

    • Context :环境类

    • Strategy:抽象策略类

    • ConcreteStrategy:具体策略类

      策略模式和状态模式常用于处理业务比较繁杂的场景,因为业务经常变更,有时候随着业务堆积,会出现大量的if...else,造成代码可读性变差,所以可以使用策略模式和状态模式等设计模式进行业务解耦,提高代码可读性

    2、典型例子实现

    业务场景:提供一个统一的页面,嵌套各个子系统,点击各个子系统时候,会进行业务处理,然后进行跳转

    业务听起来很简单,所以就简单敲下代码:

     public ModelAndView toSysPage(@RequestParam("type")String type, HttpServletRequest request){
            String viewName = "login/unifyLogin";
            String isCaLogin = request.getParameter(IS_CA_LOGIN);
            if (!StringUtils.isEmpty(isCaLogin) && "true".equalsIgnoreCase(isCaLogin)) {
                if (SysTypeEnum.SYS_APPR_CONTROL.getType().equals(type) ) {
                    viewName = "login/yzsCA";
                } else if(SysTypeEnum.SYS_APPR_UNION_CONTROL.getType().equals(type) ) {
                    viewName = "login/ydblCA";
                } else if(SysTypeEnum.SYS_APPR_UNIFY_WEB.getType().equals(type) ) {
                    viewName = "login/jsgcCA";
                }
            }
    
            if (SysTypeEnum.SYS_APPR_CONTROL.getType().equals(type) && (StringUtils.isEmpty(isCaLogin) || !"true".equals(isCaLogin))) {
                viewName = "login/yzsLogin";
            } else if(SysTypeEnum.SYS_APPR_UNION_CONTROL.getType().equals(type)  && (StringUtils.isEmpty(isCaLogin) || !"true".equals(isCaLogin))) {
                viewName = "login/ydblLogin";
            } else if(SysTypeEnum.SYS_APPR_UNIFY_WEB.getType().equals(type)  && (StringUtils.isEmpty(isCaLogin) || !"true".equals(isCaLogin))) {
                viewName = "login/jsgcLogin";
            }
    
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName(viewName);
            return modelAndView;
        }
    

    然后,和现场沟通,发现还要增加系统,业务也要增加,所以就要增加if...else的数量,业务一堆积,代码就变得很杂,不好维护,所以用策略模式进行改进

    • 定义元注解:
    
    import org.springframework.stereotype.Service;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited  //子类可以继承此注解
    public @interface SysType {
        String type();
    }
    
    
    • 写个策略接口
    import org.springframework.web.servlet.ModelAndView;
    import java.util.Map;
    
    public interface SysHandler {
        ModelAndView invokeModelAndView(Map<String,Object> params);
    }
    
    • 各个系统都实现接口,进行不同的业务处理,@SysType(type = "sys1")表示系统type,@Component记得加上,才可以加到Spring容器里
    @SysType(type = "sys1")
    @Component
    public class ApprControlSysHandler implements SysHandler{
    
        @Override
        public ModelAndView invokeModelAndView(Map<String,Object> params) {
            //...
            return modelAndView;
        }
    }
    
    
    • 在一个@Service类里,将实现SysHandler接口的类都装载到Spring容器
    public static Map<String, SysHandler> sysHandlerMap = new HashMap<String, SysHandler>(16);
    
        @Autowired
        ApplicationContext applicationContext;
    
        /**
         * 装载到Spring容器
         * @Author nicky
         * @Date 2020/06/23 17:47
         * @Param [applicationContext]
         * @return void
         */
        @PostConstruct
        public void buildSysHandlerMap() {
            Map<String, Object>  map = applicationContext
                    .getBeansWithAnnotation(SysType.class);
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Class<SysHandler> sysHandlerClass = (Class<SysHandler>)entry.getValue().getClass()  ;
                String type = sysHandlerClass.getAnnotation(SysType.class).type();
                sysHandlerMap.put(type,applicationContext.getBean(sysHandlerClass));
            }
        }
    
    
    • 调用,进行改造,代码简洁很多
    public ModelAndView toSysPage(String type, HttpServletRequest request){
            Assert.notNull(type, "type can not null");
              SysHandler sysHandler = sysHandlerMap.get(type);
              Map<String, Object> params = new HashMap<String, Object>(16);
              params.put("isCaLogin", isCaLogin);
              params = Collections.unmodifiableMap(params);
              return modelAndView = sysHandler.invokeModelAndView(params);
        }
    

    看了类图,也很清晰,这是策略模式的简单应用,有什么问题欢迎指出
    在这里插入图片描述

  • 相关阅读:
    Windows Service开发介绍
    解决Vuex持久化插件-在F5刷新页面后数据不见的问题
    selenium+python 安装使用
    字符串拆分姓名、电话、省市区逻辑
    常用正则表达式大全——包括校验数字、字符、特殊密码过滤
    uni-app 地图初用 map
    前端常见手写笔试题
    数组去重和排序
    js获取当前时间年份,处理年月日
    js循环匹配组合成新对象或js循环组合新数据
  • 原文地址:https://www.cnblogs.com/mzq123/p/13204599.html
Copyright © 2011-2022 走看看