美文网首页
如何优雅地处理switch-case

如何优雅地处理switch-case

作者: 梅肯羅斯 | 来源:发表于2020-01-21 22:37 被阅读0次

    使用注解和多态。

    思路:将自定义注解打在相应的处理器上,在Service类初始化时,自动扫描打了响应注解的处理器类,并保存下来,然后通过具体的传参取出具体的类来处理。

    具体看这个例子,现有一批资源Pojo类,资源Pojo主要有2个属性,主键resourceId和资源类型resourceType,现要根据不同的资源类型用resourceId去查不同的接口,返回资源的详细信息,返回的信息都是每个资源都会有的,比如资源名称。

    资源Pojo的定义是:

    class ResourcePojo{
        private Long resourceId;
        private EnumResource resourceType;
    }
    

    再来定义一个查询资源接口:

    interface IResourceInfoGetter{
        //根据单个资源查询
        ResourceModel getResourceInfo(ResourcePojo resource);
        //根据多个资源查询
        List<ResourceModel> getResourceInfoList(List<ResourcePojo> resources);
    }
    
    class ResourceModel{
        private Long resourceId;
        private Integer resourceType;
        //这里为了简洁就只写个资源名称,但其实可能还有更多的资源信息。
        private String resourceName;
    }
    
    /**
    * 枚举中有4个值的资源类型,分别表示机票、汽车票、长途汽车票、火车票的资源
    */
    enum EnumResource{
        FLIGHT,BUS, LONG_DISTANCE_BUS,TRAIN;
    }
    

    现在可以开始写代码了,这里还有要注意的东西就是BUS,LONG_DISTANCE_BUS这两种虽然是不同资源,但是查询的接口是同一个,所以虽然枚举值有4个,但是外部接口其实只有3个。

    //新增注解
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @interface ResourceType {
        EnumResource type();
    }
    
    //把注解打到对应的类上
    @ResourceType(type = EnumResource.FLIGHT)
    public class FlightResourceInfoGetter implements IResourceInfoGetter {
           ...
    }
    
    //service类
    @Service
    public class ResourceInfoGetter implements IResourceInfoGetter {
        private final static Map<EnumResource, IResourceInfoGetter> GETTER_STORE = new EnumMap<>(EnumResource.class);
    
        //有Getter所在包的包名
        private final static String PACKAGE_NAME = "xxx";
        //自动扫描带有自定义注解的类
        @PostConstruct
        private void init() {
            //需要引入第三方jar包 org.reflections
            Reflections reflections = new Reflections(PACKAGE_NAME);
            //获取包下所有IResourceInfoGetter
            Set<Class<? extends IResourceInfoGetter>> classes = reflections.getSubTypesOf(IResourceInfoGetter.class);
            for (Class<? extends IResourceInfoGetter> clazz : classes) {
                //因为对象是被spring管理的,所以需要通过applicationContext拿bean。
                //为了解耦ApplicationContext和该类关系,使用了一个SpringContextHolder类。
                GETTER_STORE.put(clazz.getAnnotation(ResourceType.class).type(), SpringContextHolder.getBean(clazz));
            }
        }
        //根据不同的resources调用不同接口取出信息
        public List<ResourceModel> getResourceInfoList(List<ResourcePojo> resources){
            Map<IResourceInfoGetter, List<ResourcePojo>> getterMap = resources.stream().collect(Collectors.groupingBy(r -> GETTER_STORE.get(r.getResourceType())));
            List<ResourceModel> result = new ArrayList<>(resources.size());
            for (Map.Entry<IResourceInfoGetter, List<ResourcePojo>> entry : getterMap.entrySet()) {
                result.addAll(entry.getKey().getResourceInfoList(entry.getValue()));
            }
            return result;
        }
    }
    
    
    

    现在再来看如果新增一种resourceType,需要改动哪些地方:

    1.Enum类新增一种资源类型。
    2.新增一个实现IResourceInfoGetter的类 (类上的注解 ),用来查询第五种资源。

    代码比switch-case简洁,扩展性也比switch-case强。

    总结:利用多态和注解来替代switch-case代码块。

    相关文章

      网友评论

          本文标题:如何优雅地处理switch-case

          本文链接:https://www.haomeiwen.com/subject/jrtlzctx.html