在项目中, 存在某处代码使用大量if-elseif的结构,用于判断类型,然后做相应的处理,接手这段代码的时候,阅读起来十分费劲,而且扩展起来也很困难,于是考虑使用策略模式进行重构。
由于场景中是使用状态或类型来进行相关逻辑处理的,所以定义接口时,声明一个方法,返回类型或者状态
public interface TaskMessageService{
/**
* 获取类型
*/
String getType();
}
然后定义处理方法
public interface TaskMessageService{
/**
* 获取类型
*/
String getType();
/**
* 生成任务消息
* @Param record 记录详情
*/
String generateTaskMessage(Record record);
}
然后各个类型的具体实现类去继承此接口,如果要重构的方法可以利用模板方法模式进行重构,也可以用模板类实现该接口,实现完之后,将相关的处理类放入到Spring容器中去管理。
接着可以创建一个工厂类,用于获取各个类型的具体实现。
@Service
public class TaskMessageServiceFactory{
// 获取所有被Spring容器管理的TaskMessageService,给一个初始的空数组,避免没有实现的时候出现空指针情况。
@Autowired
private List<TaskMessageService> taskMessageServiceList = Collections.emptyList();
// Type和TaskMessageService的映射
private Map<String,TaskMessageService> serviceMap = Collections.emptyMap();
// 处理Type和TaskMessageService的映射关系
@PostConstruct
public void init(){
serviceMap = taskMessageServiceList.stream().collect(Collectors.toMap(TaskMessageService::getType, e->e));
}
// 过去Type对应的TaskMessageService实例
public TaskMessageService getTaskMessageService(String type){
// 此处也可以使用Map的getOrDefault方法,在没有对应类型的时候给一个兜底的处理,根据实际情况进行处理
return serviceMap.get(type);
}
}
也可以使用ApplicationContextWare来获取TaskMessageService对应的实例
@Service
public class TaskMessageServiceFactory implements ApplicationContextAware {
private Map<String,TaskMessageService> serviceMap = Collections.emptyMap();
public TaskMessageService getTaskMessageService(String type){
return serviceMap.get(type);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// applicationContext.getBeansOfType获取到的是一个Map,可以为Service的name
serviceMap = applicationContext.getBeansOfType(TaskMessageService.class).values().stream().collect(Collectors.toMap(TaskMessageService::getMessageType, e->e));
}
}
也可以通过构造函数来处理
@Service
public class TaskMessageServiceFactory {
private Map<String,TaskMessageService> serviceMap = Collections.emptyMap();
public TaskMessageServiceFactory(List<TaskMessageService> taskMessageServiceList ){
this.serviceMap = taskMessageServiceList.stream().collect(Collectors.toMap(TaskMessageService::getMessageType, e->e));
}
public TaskMessageService getTaskMessageService(String type){
return serviceMap.get(type);
}
}
具体调用的时候通过Type就能直接获取相关的处理类,在代码的可读性和扩展性上都有很大的提升。
......
@Autowired
private TaskMessageServiceFactory taskMessageServiceFactory;
......
......
Recored record = getRecord(id);
String taskMessage = taskMessageServiceFactory.get(record.getType()).generateTaskMessage(record);
......
......
Spring中的Bean除了单例模式,还有多例等模式,我们目前定义的Factory是单例模式,如果后面的开发人员使用到了多例模式,那么初始化的时候就缓存起来的实例对于调用者来说肯定是单例的,这明显是不太合适的。
在单例模式中要获取多例的Bean,需要使用BeanFactory的getBean方法。
所以目前有两种扩展策略,一种是将映射关系保存为Map<Srting,Class<? extends TaskMessageService>>,每次获取实例对象都是通过BeanFactory去获取。
@Service
public class TaskMessageServiceFactory {
private Map<String,Class<? extends TaskMessageService>> serviceMap = Collections.emptyMap();
private final BeanFactory beanFactory;
public TaskMessageServiceFactory(List<TaskMessageService> taskMessageServiceList,BeanFactory beanFactory){
this.serviceMap = taskMessageServiceList.stream()
.collect(Collectors.toMap(TaskMessageService::getMessageType, e->e.getClass()));
this.beanFactory = beanFactory;
}
public TaskMessageService getTaskMessageService(String type){
return beanFactory.getBean(serviceMap.get(type));
}
}
还有一种是判断实例是否为单例,如果是单例,则缓存取来,否则通过BeanFactory获取
BeanFactory通过了isSingleton()的接口,通过beanName判断该Bean是否为单例模式
@Service
public class TaskMessageServiceFactory {
private Map<String,TaskMessageService> singletonInstanceMap;
private Map<String,Class<? extends TaskMessageService>> noSingletonClassMap ;
private final BeanFactory beanFactory;
public TaskMessageServiceFactory(Map<String,TaskMessageService> instanceMap,BeanFactory beanFactory ){
// 根据是否单例进行分组
Map<Boolean, List<Map.Entry<String, TaskMessageService>>> collect =
instanceMap.entrySet().stream().collect(Collectors.groupingBy(e -> beanFactory.isSingleton(e.getKey())));
// 处理单例映射
List<Map.Entry<String, TaskMessageService>> entries = collect.get(Boolean.TRUE);
this.singletonInstanceMap = CollectionUtils.isEmpty(entries) ? Collections.emptyMap() :
entries.stream().map(Map.Entry::getValue).collect(Collectors.toMap(TaskMessageService::getType,
e -> e));
entries = collect.get(Boolean.FALSE);
// 处理非单例映射
this.noSingletonClassMap = CollectionUtils.isEmpty(entries) ? Collections.emptyMap() :
entries.stream().map(Map.Entry::getValue).collect(Collectors.toMap(TaskMessageService::getType,
TaskMessageService::getClass));
this.beanFactory = beanFactory;
}
public TaskMessageService getTaskMessageService(String type){
if (singletonInstanceMap.containsKey(type)) {
return singletonInstanceMap.get(type);
} else if (propertiesInstanceMap.containsKey(type)) {
// 非单例则通过BeanFactory获取实例
return beanFactory.getBean(propertiesInstanceMap.get(type));
} else {
// 给默认值
return singletonInstanceMap.get("default");
}
}
}