springboot's Excessive if else Solutions

In practical development projects, we often encounter multiple ifelse judgment statements. For simple projects, we can also meet the requirements table. However, for projects with frequent changes in requirements, this will lead to code redundancy and difficult to maintain, so it is not recommended to adopt this method. Here is a solution to the springboot project.

1 Basic Code

1.1 service interface code

public interface OrderService {
    String handle(OrderDTO orderDTO);
}

1.2 OrderDTO Code

public class OrderDTO {
    private String code;
    private BigDecimal price;
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

Two ways of implementation

2.1 Traditional Ways

   public String traditionalHandle(OrderDTO orderDTO){
        String type = orderDTO.getType();
        if ("1".equals(type)){
            return "Handling common types";
        }if ("2".equals(type)){
            return "Types of Group Purchase Processing";
        }if ("2".equals(type)){
            return "Types of Promotion Handled";
        }
        return "error handling";
    }

2.2 Strategic Model

    @Autowired
    private HandlerContext handlerContext;
    @Override
    public String handle(OrderDTO orderDTO) {
        AbstractHandler handler = handlerContext.getInstance(orderDTO.getType());
        return handler.handler(orderDTO);
    }

3 Policy + applicationContext Container Approach

3.1 Implementation Ideas

  1. Scanning multiple implementation classes of corresponding abstract classes
  2. Store corresponding implementation classes in hashMap containers and provide processing classes for external encapsulation
  3. Call processing classes to complete business requirements

3.2 Code Implementation

3.2.1HandlerProcessor 

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @author shuxibing
 * @date 2019/7/31 15:03
 * @uint d9lab
 * @Description: This class mainly refers to injecting scanned information into the application context container.
 */
@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {

    /**
     * Scanning hanglerMap annotators into containers
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String,Class> handlerMap=new HashMap<>(3);
        ClassScaner.scan(Const.HANDLER_PACAGER,HandlerType.class).forEach(clazz->{
            String type = clazz.getAnnotation(HandlerType.class).value();
            handlerMap.put(type,clazz);
        });
        HandlerContext context=new HandlerContext(handlerMap);
        beanFactory.registerSingleton(HandlerContext.class.getName(),context);
    }
}

3.2.2 AbstractHandler and Implementation Class

public abstract class AbstractHandler {
    public abstract String handler(OrderDTO orderDTO);
}
@Component
@HandlerType("1")
public class NormalHandler extends AbstractHandler {
    @Override
    public String handler(OrderDTO orderDTO) {
        return "Handling Ordinary Orders";
    }
}
@Component
@HandlerType("2")
public class GroupHandler extends AbstractHandler {
    @Override
    public String handler(OrderDTO orderDTO) {
        return "Types of Group Purchase Processing";
    }
}
@Component
@HandlerType("3")
public class PromotionHandler extends AbstractHandler {
    @Override
    public String handler(OrderDTO orderDTO) {
        return "Processing Group Purchase Orders";
    }
}

3.2.3 Annotations + Scanning

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface HandlerType {
    String value();
}
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.*;

/**
 * @author shuxibing
 * @date 2019/7/31 15:07
 * @uint d9lab
 * @Description:
 */
public class ClassScaner implements ResourceLoaderAware {
    private final List<TypeFilter> includeFilters=new LinkedList<>();
    private final List<TypeFilter> excludeFilters=new LinkedList<>();

    private ResourcePatternResolver resourcePatternResolver=new PathMatchingResourcePatternResolver();
    private MetadataReaderFactory metadataReaderFactory=new CachingMetadataReaderFactory(this.resourcePatternResolver);


    public static Set<Class<?>> scan(String[] basepackages, Class<? extends Annotation>...annoations) {
        ClassScaner cs=new ClassScaner();
        //Annotations to be scanned
        if (ArrayUtils.isNotEmpty(annoations)){
            for (Class anno:annoations){
                cs.addIncludeFilter(new AnnotationTypeFilter(anno));
            }
        }
        Set<Class<?>> classes=new HashSet<>();
        for (String s:basepackages){
            classes.addAll(cs.doScan(s));
        }
        return classes;
    }
    public static Set<Class<?>> scan(String basePackage,Class<? extends Annotation> ...annoations){
        return scan(new String[]{basePackage},annoations);
    }

    private Set<Class<?>> doScan(String basePackage) {
        Set<Class<?>> classes=new HashSet<>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage)) + "/**/*.class";
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
            for (Resource resource : resources) {
                if (resource.isReadable()){
                    MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                    if ((includeFilters.size()==0&&excludeFilters.size()==0)||matches(metadataReader)){
                        try {
                            classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }catch (IOException e){
           throw new BeanDefinitionStoreException("IO failure during classpath scanning",e);
        }
        return classes;
    }

    protected boolean matches(MetadataReader metadataReader) throws IOException {
         for(TypeFilter tf:this.excludeFilters){
             if (tf.match(metadataReader,this.metadataReaderFactory)){
                 return false;
             }
         }
         for (TypeFilter tf:this.includeFilters){
             if (tf.match(metadataReader,this.metadataReaderFactory))
                return true;
         }
         return false;
    }

    /**
     * Setting up parsers
     * @param resourceLoader
     */
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourcePatternResolver= ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        this.metadataReaderFactory=new CachingMetadataReaderFactory(resourceLoader);
    }



    public void addIncludeFilter(TypeFilter typeFilter){
        this.includeFilters.add(typeFilter);
    }

    public void addExcludeFilter(TypeFilter typeFilter){
        this.excludeFilters.add(0,typeFilter);
    }

    public final ResourceLoader getResourceLoader(){
        return this.resourcePatternResolver;
    }

    public void resetResourceLoader(){
        this.includeFilters.clear();
        this.excludeFilters.clear();
    }
}

3.2.4 Encapsulates object classes for obtaining applicationContext

@Component
public class BeanTool implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    //Automatic Initialization Injection applicationContext
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        if (applicationContext==null){
            applicationContext=context;
        }
    }

    /**Getting types by abbreviating bean s
     *
     * @param name
     * @return
     */
    public static Object getBean(String name){
        return applicationContext.getBean(name);
    }

    public static <T> T getBean(Class<T> clazz){
        return applicationContext.getBean(clazz);
    }
}

3.2.5 Policy Pattern Processing Class

public class HandlerContext {
    private Map<String,Class> handlerMap;

    public HandlerContext(Map<String, Class> handlerMap) {
        this.handlerMap = handlerMap;
    }

    public AbstractHandler getInstance(String type){
        Class clazz=handlerMap.get(type);
        if (clazz==null){
            throw new IllegalArgumentException("The input parameter type is problematic:"+type);
        }
        return (AbstractHandler) BeanTool.getBean(clazz);
    }
}

3.2.6 parameter class

public class Const {
    public static final String HANDLER_PACAGER="com.shu.example.strategymodel";
}

 

Tags: Java SpringBoot Apache

Posted on Wed, 09 Oct 2019 09:10:22 -0700 by V