如何优雅地处理switch-case

使用注解和多态。

思路:将自定义注解打在相应的处理器上,在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代码块。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容