使用注解和多态。
思路:将自定义注解打在相应的处理器上,在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代码块。
网友评论