笔者在开发的时候遇到一个问题
- 一个类中存在多个实现
- 需要提供一个窗口,让外部调用的时候无需知道众多子类的实现
因为项目使用Spring开发的,所以笔者这里打算采用ApplicationContextAware提供的接口,获取到全部子类。并提供一个Proxy屏蔽这些子类的差异,让调用只通过Proxy完成。
1、代理设计模式和策略设计模式区别
这里说明下为啥不用策略设计模式而是选择代理设计模式,因为策略设计模式更趋向于实现一个目标的不同做法,例如我要对一系列数字进行排序,可以采用冒泡、希尔以及归并扽等等;而代理设计模式主要针对对象的访问控制,tong's因为代理类与被代理类实现的是同一个接口,因此代理类与被代理类的结构是相同的,同样的接口外部调用者只需要知道调用哪个方法而无需知道具体实现。
2、通过继承ApplicationContextAware获取Spring管理的对象
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext arg) throws BeansException {
SpringUtils.applicationContext = arg;
}
public static <T> Map<String, T> getSubClassByType(Class<T> classObj) {
return SpringUtils.applicationContext.getBeansOfType(classObj);
}
}
3、在提供的Proxy类中,使用上面实现了ApplicationContextAware的类获取Spring容器管理中的Bean
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Map;
@Service
@DependsOn({"springUtils"})
public class WorkerProxyService implements WorkerManagerService {
private Map<String, WorkerManagerService> beanManagerMap;
@PostConstruct
public void init() {
beanManagerMap = SpringUtils.getSubClassByType(WorkerManagerService.class);
}
@Override
public void print() {
getManagerByOneStrategy().print();
}
private WorkerManagerService getManagerByOneStrategy() {
/* 实现某种遍历map获取WorkerManagerService 的策略*/
return beanManagerMap.get("");
}
}
在代理类中,由几点需要注意:
- 因为代理类需要使用到SpringUtils,所以最好使用@DependsOn避免代理类在于SpringUtils创建;
- 获取到子类实现是一个Map,其中key为bean名字,value为子类的引用;
- 考虑到子类的实现是一个Map,需要采取某种策略,例如我这里的getManagerByOneStrategy()去获取到Map中对应的实现(当然如果考虑到需要每个实现都执行一次可以省略这一步)
- 因为是代理类,所以proxy需要实现和父类同样的接口。