java实现同个接口多个实现类通用策略模式
项目业务中,有多个平台,多个平台直接有相同的业务,只有一个接口入口,但是
不同的平台入口,虽然接口相同,参数相同,但是各自的具体实现不同,唯一能区分来源的
是请求头中有标识平台的字段:from
最简单的方法是对from进行判断,
if(from==1){
}
if(from==2){
}
......
虽然这样也能实现,但是明显多余,且不好扩展,我们只需要关注与具体业务实现即可
通过from标识,来自动判断执行具体的实现方法
思路:
1、定义个通用的策略实现方法,spingboot注入的时候扫描到哪些类是需要多实现的
2、需要多实现的每个实现类标记下平台的自定义注解,用于识别from具体执行的类
策略父类
定义父类,用于多实现的类能被扫描到
public interface BaseStrategy {}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SysPlatform {SysPlatformConstant.SysPlatformEnum from() default SysPlatformConstant.SysPlatformEnum.ALL;}
public interface IFenceService extends BaseStrategy {void updateFence(IUpdateFenceVO fence);
}
@Slf4j
@Service
@RequiredArgsConstructor
@SysPlatform(from = SysPlatformConstant.SysPlatformEnum.AGRICULTURE_PLATFORM)
public class AgrFenceServiceImpl implements IFenceService {@Overridepublic void updateFence(IUpdateFenceVO fence) {sout("执行了围栏服务具体实现类1");}
}
@Slf4j
@Service
@RequiredArgsConstructor
@Primary
public class FenceServiceImpl implements IFenceService {@Overridepublic void updateFence(IUpdateFenceVO fence) {sout("执行了围栏服务具体实现类2");}
}
@Slf4j
@Service
@SysPlatform(from = SysPlatformConstant.SysPlatformEnum.ELDER_PLATFORM)
public class ElderFenceServiceImpl implements IFenceService {@Overridepublic void updateFence(IUpdateFenceVO fence) {sout("执行了围栏服务具体实现类3");}
}
策略实现具体服务上下文代码
@Component
@RequiredArgsConstructor
@Slf4j
public class BaseStrategyContext {@Autowired(required = false)private List<BaseStrategy> productStrategyList;private static BaseStrategyContext baseStrategyContext;@PostConstructpublic void init() {baseStrategyContext = this;baseStrategyContext.productStrategyList = this.productStrategyList;}public static <T> T build(Class<T> parent) {HttpServletRequest request = WebUtil.getRequest();String fromType = request.getHeader(SecurityConstant.OLD_FROM);return getRunServiceClass(parent, fromType);}public <T> T create(Class<T> parent, String fromType) {return getRunServiceClass(parent, fromType);}private static <T> T getRunServiceClass(Class<T> parent, String fromType) {SysPlatformConstant.UserFromEnum byFromType = SysPlatformConstant.UserFromEnum.getByFromType(fromType);List<Class<?>> subClasses = findSubClasses(parent);T productStrategy = null;for (Class<?> subClass : subClasses) {if (subClass.getAnnotation(SysPlatform.class) != null) {SysPlatform annotation = subClass.getAnnotation(SysPlatform.class);SysPlatformConstant.SysPlatformEnum from = annotation.from();if (from.getPlatformId().equals(byFromType.getPlatformEnum().getPlatformId())) {productStrategy = (T) SpringUtil.getBean(subClass);break;}} else {productStrategy = (T) SpringUtil.getBean(subClass);}}AssertUtil.notNull(productStrategy, CustomReturnEnum.NOT_ALLOW_OPERATION);return productStrategy;}private static List<Class<?>> findSubClasses(Class<?> parent) {List<Class<?>> subclasses = new ArrayList<>();for (BaseStrategy t : baseStrategyContext.productStrategyList) {try {Class<?> clazz = t.getClass();if (parent.isAssignableFrom(clazz) && !clazz.equals(parent)) {subclasses.add(clazz);}} catch (Exception e) {log.error("基础策略上下文错误:{}", ExceptionUtil.getStackStr(e));}}return subclasses;}}
具体的实现方法示例
方法1,用BaseStrategyContext 的create方法private final BaseStrategyContext baseStrategyContext;@GetMapping("/listStepNum")public OStepMiniappStaticsVO listStepNum(IStepStatisticVO iStepStatisticVO) {String from = UserUtil.getFrom();return baseStrategyContext.create(StepService.class, from).listStepNum(iStepStatisticVO);}----------------------------------------------------------------------------------方法2,用BaseStrategyContext 的build 静态方法,
使用静态方法,controller层不用注入基本策略上下文,可以直接使用@PostMapping("/update")public void updateById(@RequestBody @Valid IUpdateFenceVO fence) {BaseStrategyContext.build(IFenceService.class).updateFence(fence);}

通过枚举的方式也能多实现不同的方式
业务背景:相同的数据,但是不同的客户,具体的实现是不一样的,通过客户代码去区分,走不同的具体实现
private void pushData(List<HealthPushVO> resultList) {Map<Long, List<HealthPushVO>> pushMap = resultList.stream().collect(Collectors.groupingBy(HealthPushVO::getTenantId));pushMap.forEach((tenantId, value) -> {ListenerTableEnum customPush = ListenerTableEnum.getByValue(tenantId.toString());BaseMqProducer producer = SpringUtil.getBean(customPush.getServiceName());producer.healthPush(value, tenantId);});}
@Getter
@AllArgsConstructor
public enum ListenerTableEnum {ZF160("ZF160", "ZF160Push", "ZF160"),ZF161("ZF161", "ZF161Push", "ZF161"),...................public static ListenerTableEnum getByValue(String type) {if (type == null) {return ZF160;}for (ListenerTableEnum val : values()) {if (val.customCode.equals(type)) {return val;}}return ZF160;}private final String customCode;private final String serviceName;private final String customName;
}
public interface BaseMqProducer {void pushData(List<HealthPushVO> oCardCallBackVOS, Long tenantId);
}
@Slf4j
@Component("ZF160Push")
@RequiredArgsConstructor
public class ZF160Producer implements BaseMqProducer {@Overridepublic void pushData(List<HealthPushVO> oCardCallBackVO, Long tenantId) {}
}
@Slf4j
@Component("ZF161Push")
@RequiredArgsConstructor
public class ZF161Producer implements BaseMqProducer {@Overridepublic void pushData(List<HealthPushVO> oCardCallBackVO, Long tenantId) {}
}
