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) { }
}