1. Introduction to strategy mode

For more information on design patterns, see my Design Patterns Notes column: Design Patterns series blog

Strategy pattern: Define a series of algorithms, then encapsulate each algorithm and make them interchangeable. That is, encapsulate a set of algorithms into a set of policy classes. Policy pattern is an object behavior pattern. The strategy pattern conforms to the “open closed principle”

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.

The policy mode includes the following roles:

  • Context: Environment class

  • Strategy: Abstract policy class

  • ConcreteStrategy: ConcreteStrategy class

    Policy mode and state mode are commonly used to deal with complex business scenarios, because the business changes frequently, and sometimes as the business piles up, there will be a large number of if… Else, resulting in poor code readability, so you can use design patterns such as policy mode and state mode for business decoupling to improve code readability

2. Typical example implementation

Business scenario: provide a unified page, nested each subsystem, click each subsystem, the service will be processed, and then jump to

Business sounds simple, so simply type the code:

 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;
    }
Copy the code

Then, after communicating with the site, we found that we need to increase the system and business, so we need to increase if… The number of else, once the business piled up, the code became very complicated and difficult to maintain, so use the policy mode to improve

  • Define meta annotations:

import org.springframework.stereotype.Service;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited  // Subclasses can inherit this annotation
public @interface SysType {
    String type(a);
}

Copy the code
  • Write a policy interface
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;

public interface SysHandler {
    ModelAndView invokeModelAndView(Map<String,Object> params);
}
Copy the code
  • Each system implements interfaces for different business processes,@SysType(type = "sys1")@Component = system type @Component = Spring
@SysType(type = "sys1")
@Component
public class ApprControlSysHandler implements SysHandler{

    @Override
    public ModelAndView invokeModelAndView(Map<String,Object> params) {
        / /...
        returnmodelAndView; }}Copy the code
  • You can create a new factory class or proxy class and load all the classes that implement the SysHandler interface into a sysHandlerMap, which can be made into a singleton
public static Map<String, SysHandler> sysHandlerMap = new HashMap<String, SysHandler>(16);

    @Autowired
    ApplicationContext applicationContext;

    /** * loaded into the Spring container *@Author nicky
     * @Date2020/06/23 saveth *@Param [applicationContext]
     * @return void
     */
    @PostConstruct
    public void buildSysHandlerMap(a) {
        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)); }}Copy the code
  • Call, transformation, code is much simpler
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);
    }
Copy the code

Look at the class diagram, it is also very clear, this is a simple application of the policy pattern, welcome to point out any problems