策略模式+元註解方式替代大量if else寫法

一、策略模式簡介

設計模式的知識能夠參考個人設計模式筆記專欄:設計模式系列博客html

策略模式:定義一系列算法,而後將每個算法封裝起來,並將它們能夠互相替換。也就是將一系列算法封裝到一系列策略類裏面。策略模式是一種對象行爲型模式。策略模式符合「開閉原則「java

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.web

策略模式包括以下角色:算法

  • Context :環境類spring

  • Strategy:抽象策略類設計模式

  • ConcreteStrategy:具體策略類app

    策略模式和狀態模式經常使用於處理業務比較繁雜的場景,由於業務常常變動,有時候隨着業務堆積,會出現大量的if...else,形成代碼可讀性變差,因此可使用策略模式和狀態模式等設計模式進行業務解耦,提升代碼可讀性ide

二、典型例子實現

業務場景:提供一個統一的頁面,嵌套各個子系統,點擊各個子系統時候,會進行業務處理,而後進行跳轉ui

業務聽起來很簡單,因此就簡單敲下代碼:.net

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

看了類圖,也很清晰,這是策略模式的簡單應用,有什麼問題歡迎指出
在這裏插入圖片描述

相關文章
相關標籤/搜索