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);
        }
    

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

  • 相关阅读:
    XAF 有条件的对象访问权限
    XAF 顯示 UnInplace Report(設置自定義條件顯示報表,不是根據選擇ListView記錄條件顯示報表)
    XAF 如何自定义PivotGrid单元格显示文本?
    XAF 如何布局详细视图上的按钮
    XAF How to set size of a popup detail view
    XAF Delta Replication Module for Devexpress eXpressApp Framework
    XAF 帮助文档翻译 EasyTest Basics(基础)
    XAF 用户双击ListView记录时禁止显示DetailView
    XAF How to enable LayoutView mode in the GridControl in List Views
    XAF 如何实现ListView单元格批量更改?
  • 原文地址:https://www.cnblogs.com/mzq123/p/13204599.html
Copyright © 2011-2022 走看看