欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用策略模式消除代码中繁杂的if-else

程序员文章站 2022-03-09 16:19:02
...

说明

基于SpringBoot,使用策略模式进行封装,意在消除代码中繁杂的if-else。

示例

public interface SchoolService {
    String handler();
}

@Component
@HandlerOrder(type = SchoolService.class)
public class ChinaSchoolServiceImpl implements SchoolService{
    @Override
    public String handler() {
        return "ChinaSchool";
    }
}
public interface StudentService {
    String handler();
}
@Component
@HandlerOrder(type = StudentService.class, value = "HighSchool")
public class HighSchoolStudentServiceImpl implements StudentService{
    @Override
    public String handler() {
        return "HighSchoolStudent";
    }
}
@Component
@HandlerOrder(type = StudentService.class, value = "University")
public class UniversityStudentServiceImpl implements StudentService{
    @Override
    public String handler() {
        return "UniversityStudent";
    }
}
@SpringBootTest
@RunWith(SpringRunner.class)
public class HandlerTest {
    @Autowired
    private HandlerContext handlerContext;

    @Test
    public void studentServiceTest() {
        assert "HighSchoolStudent".equals(handlerContext.getInstance(StudentService.class, "HighSchool").handler());
        assert "UniversityStudent".equals(handlerContext.getInstance(StudentService.class, "University").handler());
    }

    @Test
    public void schoolServiceTest() {
        assert "ChinaSchool".equals(handlerContext.getInstance(SchoolService.class, "").handler());
    }
}

实现

import java.lang.annotation.*;

/**
 * @Description: 处理器注解类
 * @Author: LiG
 * @Date: 2019/9/18 11:28
 * @Version: 1.0
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandlerOrder {
    /**
     * 处理器类型
     * @return
     */
    Class type();

    /**
     * 某一类型下唯一值
     * @return
     */
    String value() default "";
}
import com.google.common.base.Preconditions;
import com.***.base.component.util.BeanUtil;

import java.util.Map;

/**
 * @Description: 处理器上下文
 * @Author: LiG
 * @Date: 2019/9/18 14:28
 * @Version: 1.0
 */
public class HandlerContext{
    private Map<Class, Map<String, Class>> context;

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

    /**
     * 获取处理器实例
     * @param type
     * @param value
     * @param <T>
     * @return
     */
    public <T> T getInstance(Class<T> type, String value) {
        Class clazz = context.get(type).get(value);
        Preconditions.checkNotNull(clazz, "Failed to get the processor, Invalid type or value!!!");
        return (T) BeanUtil.getBean(clazz);
    }
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: 处理器上下文设置
 * @Author: LiG
 * @Date: 2019/9/18 15:02
 * @Version: 1.0
 */
public class HandlerProcessor implements BeanFactoryPostProcessor {
    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     *
     * @param beanFactory the bean factory used by the application context
     * @throws BeansException in case of errors
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<Class, Map<String, Class>> context = new HashMap<>(16);
        Arrays.stream(beanFactory.getBeanNamesForAnnotation(HandlerOrder.class)).collect(Collectors.groupingBy(className ->
                Arrays.stream(beanFactory.getType(className).getAnnotations()).filter(annotation -> annotation instanceof HandlerOrder).
                        map(annotation -> ((HandlerOrder) annotation).type()).findFirst().get()
        )).forEach((clazz, list) -> context.put(clazz, list.stream().collect(Collectors.toMap(className ->
                Arrays.stream(beanFactory.getType(className).getAnnotations()).filter(annotation -> annotation instanceof HandlerOrder).
                        map(annotation -> ((HandlerOrder) annotation).value()).findFirst().get(),
                className -> beanFactory.getType(className), (oldValue, newValue) -> newValue))));

        HandlerContext handlerContext = new HandlerContext(context);
        beanFactory.registerSingleton(HandlerContext.class.getName(), handlerContext);
    }
}
import org.springframework.context.ApplicationContext;

/**
 * @Description: BeanUtil,提供各种applicationContext的方法的简单代理
 * @Author: LiG
 * @Date: 2019/9/19 10:32
 * @Version: 1.0
 */
public class BeanUtil {
    private static ApplicationContext applicationContext;

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

    public static void setApplicationContext(ApplicationContext applicationContext) {
        BeanUtil.applicationContext = applicationContext;
    }
}
import com.***.base.component.handler.HandlerProcessor;
import com.***.base.component.util.BeanUtil;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description: 公共组件beans
 * @Author: LiG
 * @Date: 2019/9/18 18:18
 * @Version: 1.0
 */
@Configuration
public class ComponentConfiguration implements ApplicationContextAware {
    @Bean
    @ConditionalOnProperty(prefix = "base.component", name = "handler", havingValue = "true")
    public HandlerProcessor handlerProcessor() {
        return new HandlerProcessor();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        BeanUtil.setApplicationContext(applicationContext);
    }
}