利用政策模式解決多條件問題
問題重制
這是公司代碼裡面的一個接口,我需要根據type的不同,去決定要不要存儲裡面的對象。
ini複制代碼 @Transactional(rollbackFor = Exception.class)
@Override
public boolean saveDimensionsByQuestionBankId(List<MbDimensionsDto> dimensions, Long questionBankId,Integer type) {
//如果是無次元,說明不用儲存
if(type == QuestionBankSettingTypeEnum.無次元.getValue()){
return true;
}
//如果不是,就先檢驗
checkIsDimensionsDtoLegal(dimensions);
if(type.equals(QuestionBankSettingTypeEnum.一極次元.getValue())){
dimensions.forEach(mbDimensionDto -> {
MbDimension mbDimension = new MbDimension();
BeanUtils.copyProperties(mbDimensionDto, mbDimension);
mbDimension.setQuestionBankId(questionBankId);
this.save(mbDimension);
});
return true;
}
if(type.equals(QuestionBankSettingTypeEnum.二級次元.getValue())){
//新增樹狀dimensions
dimensions.forEach(mbDimensionDto -> {
MbDimension mbDimension = new MbDimension();
BeanUtils.copyProperties(mbDimensionDto, mbDimension);
mbDimension.setQuestionBankId(questionBankId);
this.save(mbDimension);
Long fatherId = mbDimension.getId();
List<MbDimensionsDto> children = mbDimensionDto.getChildren();
if(children == null){
return;
}
children.forEach(son -> {
MbDimension mbDimensionSon = new MbDimension();
BeanUtils.copyProperties(son, mbDimensionSon);
mbDimensionSon.setQuestionBankId(questionBankId);
//新增後的dimension的id,即為chidren dimension的父親id.
mbDimensionSon.setParentId(fatherId);
this.save(mbDimensionSon);
});
});
return true;
}
return false;
}
不得不說,相當的醜陋!!
有一個學長的話在我腦子中不斷回響:“寫代碼就得優雅!!”
于是我重拾起他說了很多次的政策模式。
實戰
定義政策接口和實作類
對于儲存次元這個方法,我們不妨給他設定一個接口。
php複制代碼/**
* @author ht
*/
public interface SaveDimensionStrategy {
/**
* 目前的次元模式,是無次元還是一級次元,還是二級次元
* @return
*/
Integer getType();
/**
* 根據目前次元,進行處理
* @param dimensions
* @param questionBankId
* @return
*/
boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId);
}
我們目前有三個類,都需要實作這個接口,來進行不同的行為,在這裡就是對次元的不同操作。
無次元
由于無次元無需處理,直接傳回true即可
typescript複制代碼@Component
public class SaveNoDimensionStrategy implements SaveDimensionStrategy {
@Override
public Integer getType() {
return QuestionBankSettingTypeEnum.無次元.getValue();
}
@Override
public boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId) {
return true;
}
}
一級次元
typescript複制代碼@Component
public class SaveOneDimensionStrategy implements SaveDimensionStrategy {
@Resource
private MbDimensionService mbDimensionService;
@Override
public Integer getType() {
return QuestionBankSettingTypeEnum.一極次元.getValue();
}
@Override
public boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId) {
checkIsDimensionsDtoLegal(dimensions);
//批量添加
dimensions.forEach(mbDimensionDto -> {
MbDimension mbDimension = new MbDimension();
BeanUtils.copyProperties(mbDimensionDto, mbDimension);
mbDimension.setQuestionBankId(questionBankId);
mbDimensionService.save(mbDimension);
});
return true;
}
private void checkIsDimensionsDtoLegal(List<MbDimensionsDto> dimensions) {
dimensions.forEach(dimension -> {
if (StringUtils.isEmpty(dimension.getName())) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
if (dimension.getWeight() < 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
List<MbDimensionsDto> children = dimension.getChildren();
if (children != null && children.size() != 0) {
//遞歸校驗
checkIsDimensionsDtoLegal(children);
}
});
}
}
二級次元
scss複制代碼@Component
public class SaveTwoDimensionStrategy implements SaveDimensionStrategy {
@Resource
private MbDimensionService mbDimensionService;
@Override
public Integer getType() {
return QuestionBankSettingTypeEnum.二級次元.getValue();
}
@Override
public boolean saveDimensionStrategy(List<MbDimensionsDto> dimensions, Long questionBankId) {
checkIsDimensionsDtoLegal(dimensions);
//新增樹狀dimensions
dimensions.forEach(mbDimensionDto -> {
MbDimension mbDimension = new MbDimension();
BeanUtils.copyProperties(mbDimensionDto, mbDimension);
mbDimension.setQuestionBankId(questionBankId);
mbDimensionService.save(mbDimension);
Long fatherId = mbDimension.getId();
List<MbDimensionsDto> children = mbDimensionDto.getChildren();
if(children == null){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"二級次元中,父次元一定要有子次元");
}
children.forEach(son -> {
MbDimension mbDimensionSon = new MbDimension();
BeanUtils.copyProperties(son, mbDimensionSon);
mbDimensionSon.setQuestionBankId(questionBankId);
//新增後的dimension的id,即為chidren dimension的父親id.
mbDimensionSon.setParentId(fatherId);
mbDimensionService.save(mbDimensionSon);
});
});
return true;
}
private void checkIsDimensionsDtoLegal(List<MbDimensionsDto> dimensions) {
dimensions.forEach(dimension -> {
if (StringUtils.isEmpty(dimension.getName())) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
if (dimension.getWeight() < 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
List<MbDimensionsDto> children = dimension.getChildren();
if (children != null && children.size() != 0) {
//遞歸校驗
checkIsDimensionsDtoLegal(children);
}
});
}
}
由此可見,我們做的不過是把行為抽象成了接口,利用三個實作類去規範不同的行為。
這裡實作類都加上了@Component注解,讓它變成一個個Bean,同時Spring去管理。
定義Map和runner
現在已經有了一系列解決方案,也就是我們寫的一個個實作類。現在我們需要一個容器去把這一個個的解決方案跑起來!
見名知義,runner就是為此而生的。
我們定義一個 SaveDimensionStrategyRunner
java複制代碼@Component
public interface SaveDimensionStrategyRunner {
/**
* 根據 type 字段執行不同政策
* @return
*/
boolean saveDimension(List<MbDimensionsDto> dimensionsDtos, Long questionBankId,Integer type);
}
接下來,我們定義實作類。
typescript複制代碼/**
* 用來管理政策模式使用的bean,放入map進行管理
*/
@Configuration
public class StrategyConfig {
@Bean
public SaveDimensionStrategyRunner strategyRunner(List<SaveDimensionStrategy> strategies) {
Map<Integer, SaveDimensionStrategy> strategyMap = strategies.stream()
.collect(Collectors.toMap(SaveDimensionStrategy::getType, s -> s));
return (dimensionsDtoList,questionBankId,type) -> strategyMap.get(type).saveDimensionStrategy(dimensionsDtoList,questionBankId);
}
}
這段代碼做了幾件事情:
- 由于之前定義的strategy被打上了@Component注解,是以,他們會被spring管理,注入到這個方法的參數裡。
- 根據傳入的各個strategy,我們将他們的type設定為key,本身設定為value,放入map集合中。
- return語句中是 對SaveDimensionStrategyRunner這個接口中的方法的實作,也就是說,我們傳回的就是剛剛定義的接口的實作類,又由于加上了@Bean注解,該執行個體會被spring所管理。
使用
我們在需要這個方法的實作類中注入runner
java複制代碼 @Resource
private SaveDimensionStrategyRunner saveDimensionStrategyRunner;
然後直接調用它的方法就可以啦!
作者:nika_yo_nihao
連結:https://juejin.cn/post/7213310111624740925