发布于2021-05-30 06:59 阅读(1506) 评论(0) 点赞(6) 收藏(2)
我们在实际的业务开发中,经常会遇到这样的场景,对于不同的type,有同样的业务操作流程,只不过其中的某些操作需要根据type的不同特殊处理,这时候如果我们直接if,else判断来实现业务的话,势必会带来代码冗余重复的问题。说的太抽象,还是直接上代码吧
业务背景:实现一个计算系统,计算类型有加、减、乘、除,计算前先做校验,计算完后打印日志。
(1)新建Springboot项目
项目目录
(2)枚举类:四种运算,加减乘除
@Getter
@AllArgsConstructor
public enum OperationType {
ADD(1,"加法运算"),
SUB(2,"减法运算"),
MULTIPLY(3,"乘法运算"),
DIVIDE(4, "除法运算");
private Integer code;
private String description;
public static OperationType getOperationTypeByCode(Integer code){
for(OperationType type : OperationType.values()){
if(type.getCode().equals(code)){
return type;
}
}
return null;
}
}
(3) 抽象类AbstractOperationHandler,公用方法在抽象类里直接定义,需根据operationType判断分别开来的方法抽象化,让子类复写实现
@Slf4j
public abstract class AbstractOperationHandler< T extends BaseOperationDTO> {
protected static final ThreadLocal<BaseOperationDTO> THREAD_LOCAL_INPUT = new ThreadLocal<>();
public Integer execute(T t){
init(t);
validate(t);
Integer result = calculate();
printLog(t,result);
return result;
}
public void validate(T t){
AssertUtil.isNotNull(t.getFirstNumber(),"第一个数为空");
AssertUtil.isNotNull(t.getSecondNumber(),"第二个数为空");
}
private void init(T t){
THREAD_LOCAL_INPUT.set(t);
}
public T getInput(){
return (T) THREAD_LOCAL_INPUT.get();
}
private void printLog(T t, Integer result){
log.info("{}使用了计算服务,得到的结果是{}",t.getOperationPersonName(),result);
}
public abstract Integer calculate();
public abstract OperationType getOperationType();
}
(4)具体业务handler实现,继承AbstractOperationHandler,复写抽象方法
加法器:
@Service
public class AddHandler extends AbstractOperationHandler<CalculateDTO>{
@Override
public Integer calculate() {
return getInput().getFirstNumber() + getInput().getSecondNumber();
}
@Override
public OperationType getOperationType() {
return OperationType.ADD;
}
}
(5)工厂类:静态hashMap存储各种业务处理handler,根据前端传入的typeCode进行业务处理分发
@Service
@Slf4j
public class OperationServiceFactory {
private static final Map<OperationType, AbstractOperationHandler> handlerMap = new HashMap<>();
@Autowired
public OperationServiceFactory(List<AbstractOperationHandler> list){
for(AbstractOperationHandler handler : list){
handlerMap.put(handler.getOperationType(), handler);
}
}
public Integer execute(OperationType type, BaseOperationDTO baseOperationDTO) throws Exception {
AbstractOperationHandler handler = handlerMap.get(type);
if(handler == null){
log.warn("找不到对应的handler, type code = {}", type.getCode());
throw new Exception("操作类型错误");
}
Integer result = handler.execute(baseOperationDTO);
return result;
}
}
(6)前端controller,直接调用工厂类的execute方法得到结果,屏蔽底层实现,避免if else判断
@RestController
@RequestMapping(value = "/test")
public class TestController {
@Autowired
private OperationServiceFactory factory;
@PostMapping("/getResult")
public ApiResult getResult(@RequestBody CalculateDTO calculateDTO){
Integer result;
try {
result = factory.execute(OperationType.getOperationTypeByCode(calculateDTO.getOperationTypeCode()), calculateDTO);
} catch (Exception e) {
return ApiResult.renderError("服务器内部错误");
}
return ApiResult.renderSuccess(result);
}
}
可能会有人以为这样的实现方案是过度开发了,但是试想,如果这时候我们需要增加一种计算类型,按照我们普通的开发模式,势必对代码的侵入性很大,但是在我们的这种实现中,只需要枚举类加个值,然后自定义一个handler即可,完全不用动已有代码,所以这种分发策略加工厂模式的实现在减少代码冗余和实现代码可扩展性方面都具有较好的优势
总结:最近在实习的公司,已经遇到三次这种分发+工厂的实现了,俗话说事不过三,特此总结。
适用于不同的type具有一套业务流程,只不过其中的某些操作需要根据type的不同而分别开来的场景:例如本例中:计算需要有校验、计算、打印日志等功能,而其中校验和打印日志都是共用的业务,将其在抽象类中实现,计算的业务则只需要子类复写实现即可。工厂类根据typeCode的不同进行不同业务handler的分发。
代码地址:后续更新
原文链接:https://blog.csdn.net/qq_40820235/article/details/117326183
作者:哦八戒八戒
链接:http://www.qianduanheidong.com/blog/article/115882/62dd86761d1b1de9a65f/
来源:前端黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 前端黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-3
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!