重构嵌套的 if-else 以处理横切关注点,例如日志记录

Posted

技术标签:

【中文标题】重构嵌套的 if-else 以处理横切关注点,例如日志记录【英文标题】:refactoring nested if-else to handle cross cutting concerns like logging 【发布时间】:2021-10-31 11:58:14 【问题描述】:

在不使用太多嵌套 if 语句的情况下以更简洁的方式处理不断变化的需求是一个经典问题。 这是我当前的 javascript 代码。

fetchApiData(url)
//log before start
  Logger.logFetchStartedEvent();
  try 
    data = backendApi.get(url);
    Logger.logFetchSucceededEvent();
    return data;
   catch (error) 
    Logger.logFetchFailedEvent();
  

一切都在顺利进行。但是我收到了一个要求,对于某些特定的 URL,我们根本不想记录。

没问题。我添加了一个标志和开关,就这样结束了。

fetchApiData(url, shouldLog)
//log before start
  if(shouldLog) 
    Logger.logFetchStartedEvent();
  
  try 
    data = backendApi.get(url);
    if(shouldLog) 
      Logger.logFetchSucceededEvent();
    
    return data;
   catch (error) 
    if(shouldLog) 
      Logger.logFetchFailedEvent();
    
  

它并没有就此停止。 新要求出现并要求更改以适应以下要求

一些网址会记录所有内容 某些 url 只会记录错误 仅当 API 调用 url 是外部站点时,某些 url 才会记录 在某些情况下需要记录 fetchSucceeded 事件,在某些情况下则不需要。

我想你明白了。 我可以添加无数嵌套的 if/else 条件并完成它,但现在我确信必须有更好的方法来解决这类问题。现在我觉得一个方法会变成一个完整的 if/else 状态机神方法。

这是我想出来的

fetchApiData(url,logOnStart, logOnSuccess, logOnFailure, logOnlyExternalLink)
  //log on start
  if(logOnStart) 
    if(logOnlyExternalLink) 
      if(isExternalLink(url)) 
        Logger.logFetchStartedEvent();
      
     else 
      Logger.logFetchStartedEvent();
     
  
  try 
    data = backendApi.get(url);
    //log on success
    if(logOnSuccess) 
      // may need external url check again
      Logger.logFetchSucceededEvent();
    
    return data;
   catch (error) 
    if(logOnFailure) 
      if(errorType(error) === TimeOut)
      
        Logger.logFetchFailedTimeOutEvent();
       else if (errorType(error) === 404) 
        Logger.logFetchFailed404Event();
       else 
        Logger.logFetchFailedEvent();
      
    
  

我确实阅读了很多关于嵌套 if/else 问题的问题,但其中大多数最终都是 foo/bar 类型的示例和模糊的解释,由于缺乏经验,这对我来说没有实际意义。

请指点我正确的方向。

【问题讨论】:

您是否尝试将您的庞大职能划分为责任较小的职能? 正是我想做的,但我无法弄清楚如何正确拆分它。 这看起来像是工作代码,所以这个问题可能更适合codereview.stackexchange.com。 【参考方案1】:

你的函数应该看起来像这样:

fetchApiData(url, onEvent)
  //log on start
  onEvent(event.Start);
  try 
    data = backendApi.get(url);
    //log on success
    onEvent(event.Success, url);
    return data;
   catch (error) 
    onEvent(event.Failure, url, error);
  

编写 onEvent 回调是应该单独处理的事情。

此外,您可以将类实例 (eventHandler) 注入到您的函数中,而不是 onEvent 函数。

【讨论】:

感谢分离日志记录逻辑的想法。

以上是关于重构嵌套的 if-else 以处理横切关注点,例如日志记录的主要内容,如果未能解决你的问题,请参考以下文章

java的选择结构

面向切面编程(AOP)的理解

AOP 日志切面

Spring之AOP二

探索ABP基础架构的横切关注点

Spring AOP