策略模式与map和枚举结合实现动态调用实现类
问题来源:开发的时候,有一个接口需要根据参数的值来调用相应的方法去实现,每个方法实现的逻辑有点不一样,传统方法是用一堆if去判断调用哪个方法,显得代码不好看,通过学习策略模式解决了该问题。
实现步骤:
第一步:需要抽取出一个接口,里面放抽取出来的方法
public interface IHikResultProcessStrategy {
/**
* 解析字符串
* @param str
*/
void resultProcess(String str);
}
第二步:定义具体实现类,这里我有两个实现类,具体实现根据业务需求,我这里用打印简单代替
一:
@Service
@Slf4j
public class HikAreaIntrudeResultProcessStrategy implements IHikResultProcessStrategy {
@Override
public void resultProcess(String str) {
log.info("HikAreaIntrudeResultProcessStrategy");
}
}
二:
@Service
@Slf4j
public class HikFireDetectionResultProcessStrategy implements IHikResultProcessStrategy {
@Override
public void resultProcess(String str) {
log.info("HikFireDetectionResultProcessStrategy");
}
}
第三步:需要定义一个context类将这些实现类添加到map里面
@Component
public class HikResultProcessContext {
private final Map<String, IHikResultProcessStrategy> resultProcessStrategy;
//将实现类放在枚举里面,遍历添加到map
public HikResultProcessContext() {
resultProcessStrategy = new HashMap<>();
for (HikResultProcessStrategyEnum strategy : HikResultProcessStrategyEnum.values()) {
resultProcessStrategy.put(strategy.getKey(), strategy.getStrategy());
}
}
//需要的时候通过key去取实现类
public void getResultProcessStrategy(String strategyKey, String str) {
IHikResultProcessStrategy strategy = resultProcessStrategy.get(strategyKey);
if (strategy == null) {
throw new IllegalArgumentException("Invalid strategy key: " + strategyKey);
}
strategy.resultProcess(str);
}
}
枚举类如下:
@Getter
@AllArgsConstructor
public enum HikResultProcessStrategyEnum {
AREA_INTRUDE(1000,"areaIntrude", new HikAreaIntrudeResultProcessStrategy()),
FIRE_DETECTION(2000,"fireDetection", new HikFireDetectionResultProcessStrategy());
private final Integer code;
private final String key;
private final IHikResultProcessStrategy strategy;
}
第四步:调用
@Service
@Slf4j
public class HikEventSubServiceImpl implements IHikEventSubService {
@Autowired
private HikResultProcessContext resultProcessContext;
@Override
public void push(String bodyStr) {
Integer eventType = 1000;
log.info("eventType===>{}", eventType);
//遍历枚举去找对应的实现类实现
for (HikResultProcessStrategyEnum strategy : HikResultProcessStrategyEnum.values()) {
if (strategy.getCode().equals(eventType)){
resultProcessContext.getResultProcessStrategy(strategy.getKey(), bodyStr);
}
}
}
}
第五步:结果
2023-11-10 15:39:54.209 INFO 15856 --- [http-nio-58180-exec-2] .i.i.HikAreaIntrudeResultProcessStrategy 19 : HikAreaIntrudeResultProcessStrategy
可能会发生的问题解决:
问题:我在使用上面方法的时候想在具体的策略类接口想要利用@Autowired去注入其他类,却发现注入不进去,报空指针问题
原因:因为我在枚举类里面的策列类是通过new出来的方式,所以无法依赖spring自动注入注入其他类
解决:
第一步:引入工具类
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy(false)
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext(){return applicationContext;}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
if(SpringUtil.applicationContext == null){
SpringUtil.applicationContext = applicationContext;
}
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
第二步:改变枚举类,bean的方式通过工具类去获取
@Getter
@AllArgsConstructor
public enum HikResultProcessStrategyEnum {
AREA_INTRUDE("131588","areaIntrude", SpringUtil.getApplicationContext().getBean(HikAreaIntrudeResultProcessStrategy.class)),
FIRE_DETECTION("fireDetection","fireDetection", SpringUtil.getApplicationContext().getBean(HikFireDetectionResultProcessStrategy.class)),
SMOKE_DETECTION("smokeDetection", "smokeDetection", SpringUtil.getApplicationContext().getBean(HikSmokeDetectionResultProcessStrategy.class));
private final String code;
private final String key;
private final IHikResultProcessStrategy strategy;
}