使用注解和多態(tài)鞭光。
思路:將自定義注解打在相應(yīng)的處理器上,在Service類初始化時(shí)泞遗,自動(dòng)掃描打了響應(yīng)注解的處理器類惰许,并保存下來(lái),然后通過(guò)具體的傳參取出具體的類來(lái)處理史辙。
具體看這個(gè)例子汹买,現(xiàn)有一批資源Pojo類,資源Pojo主要有2個(gè)屬性聊倔,主鍵resourceId和資源類型resourceType晦毙,現(xiàn)要根據(jù)不同的資源類型用resourceId去查不同的接口,返回資源的詳細(xì)信息耙蔑,返回的信息都是每個(gè)資源都會(huì)有的见妒,比如資源名稱。
資源Pojo的定義是:
class ResourcePojo{
private Long resourceId;
private EnumResource resourceType;
}
再來(lái)定義一個(gè)查詢資源接口:
interface IResourceInfoGetter{
//根據(jù)單個(gè)資源查詢
ResourceModel getResourceInfo(ResourcePojo resource);
//根據(jù)多個(gè)資源查詢
List<ResourceModel> getResourceInfoList(List<ResourcePojo> resources);
}
class ResourceModel{
private Long resourceId;
private Integer resourceType;
//這里為了簡(jiǎn)潔就只寫(xiě)個(gè)資源名稱甸陌,但其實(shí)可能還有更多的資源信息须揣。
private String resourceName;
}
/**
* 枚舉中有4個(gè)值的資源類型盐股,分別表示機(jī)票、汽車票耻卡、長(zhǎng)途汽車票疯汁、火車票的資源
*/
enum EnumResource{
FLIGHT,BUS, LONG_DISTANCE_BUS,TRAIN;
}
現(xiàn)在可以開(kāi)始寫(xiě)代碼了,這里還有要注意的東西就是BUS卵酪,LONG_DISTANCE_BUS這兩種雖然是不同資源涛目,但是查詢的接口是同一個(gè)缩滨,所以雖然枚舉值有4個(gè)慈缔,但是外部接口其實(shí)只有3個(gè)现拒。
//新增注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@interface ResourceType {
EnumResource type();
}
//把注解打到對(duì)應(yīng)的類上
@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";
//自動(dòng)掃描帶有自定義注解的類
@PostConstruct
private void init() {
//需要引入第三方j(luò)ar包 org.reflections
Reflections reflections = new Reflections(PACKAGE_NAME);
//獲取包下所有IResourceInfoGetter
Set<Class<? extends IResourceInfoGetter>> classes = reflections.getSubTypesOf(IResourceInfoGetter.class);
for (Class<? extends IResourceInfoGetter> clazz : classes) {
//因?yàn)閷?duì)象是被spring管理的迎变,所以需要通過(guò)applicationContext拿bean窥翩。
//為了解耦A(yù)pplicationContext和該類關(guān)系遇汞,使用了一個(gè)SpringContextHolder類撒遣。
GETTER_STORE.put(clazz.getAnnotation(ResourceType.class).type(), SpringContextHolder.getBean(clazz));
}
}
//根據(jù)不同的resources調(diào)用不同接口取出信息
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;
}
}
現(xiàn)在再來(lái)看如果新增一種resourceType载城,需要改動(dòng)哪些地方:
1.Enum類新增一種資源類型最铁。
2.新增一個(gè)實(shí)現(xiàn)IResourceInfoGetter的類 (類上的注解 )讯赏,用來(lái)查詢第五種資源。
代碼比switch-case簡(jiǎn)潔冷尉,擴(kuò)展性也比switch-case強(qiáng)漱挎。
總結(jié):利用多態(tài)和注解來(lái)替代switch-case代碼塊。