策略模式在项目中的使用

在项目中, 存在某处代码使用大量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");
        }
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值