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 { @Override public void updateFence ( IUpdateFenceVO fence) { sout ( "执行了围栏服务具体实现类1" ) ; }
}
@Slf4j
@Service
@RequiredArgsConstructor
@Primary
public class FenceServiceImpl implements IFenceService { @Override public void updateFence ( IUpdateFenceVO fence) { sout ( "执行了围栏服务具体实现类2" ) ; }
}
@Slf4j
@Service
@SysPlatform ( from = SysPlatformConstant. SysPlatformEnum . ELDER_PLATFORM )
public class ElderFenceServiceImpl implements IFenceService { @Override public void updateFence ( IUpdateFenceVO fence) { sout ( "执行了围栏服务具体实现类3" ) ; }
}
策略实现具体服务上下文代码
@Component
@RequiredArgsConstructor
@Slf4j
public class BaseStrategyContext { @Autowired ( required = false ) private List < BaseStrategy > productStrategyList; private static BaseStrategyContext baseStrategyContext; @PostConstruct public 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 { @Override public void pushData ( List < HealthPushVO > oCardCallBackVO, Long tenantId) { }
}
@Slf4j
@Component ( "ZF161Push" )
@RequiredArgsConstructor
public class ZF161Producer implements BaseMqProducer { @Override public void pushData ( List < HealthPushVO > oCardCallBackVO, Long tenantId) { }
}