【问题标题】:Replace Multiple If\Else with Design Pattern用设计模式替换多个 If\Else
【发布时间】:2017-08-23 11:19:13
【问题描述】:

基于 SO 上的各种线程(例如 Replacing if else statement with pattern ),我知道我可以用 Command 模式替换多个 if\else 语句。

我的情况有点不同。

我有一系列Commands,只有在上一个命令不成功的情况下,我才需要执行每个Command

例如,假设我需要从假设的网页中检索文本 - 我可以使用屏幕抓取直接从页面中抓取文本,或者我可以从 API 获取文本。如果屏幕抓取不成功,我只想从 API 获取文本。换句话说,如果“scrape”命令不起作用,我只会执行“fetch”命令。

在这种情况下,我会测试抓取的 String 是否为空或等于 null,然后执行第二个 Command。如果第二个命令也不成功,我会执行第三个命令,依此类推。

重要的一点是,如果某个条件为真/假,我们只执行后续命令。每个命令的条件始终相同,但将来命令的数量可能会增加。

我无法通过通常建议的路线(使用MapCommand 接口)实现这一点,因为如果第一个失败,这将不会执行下一个Command(它也无法检查@ 987654329@是否成功)

什么设计模式可以用来解决这个问题?

【问题讨论】:

  • 如果条件是命令固有的:运行命令,使其返回true 成功。将所有命令放在一个列表中,运行该列表中的所有命令,直到第一个成功。不幸的是,Java Stream 没有takeWhile()
  • 我想你正在寻找chain of responsibility pattern

标签: java if-statement design-patterns conditional


【解决方案1】:

正如其他人所说,使用Chain of Responsibility 模式可以连续尝试不同的实现,直到成功。

假设您的 Command 有这个接口,其中处理的 Request 如果成功则返回 Result 对象,如果失败则返回 null(也可以使用布尔值或 Optional 或任何你想要的)

public interface Command{

  Result handle( Request request);
}

然后您的链式命令可以包装其他几个命令并尝试每个命令,直到某些工作正常。

public class ChainedCommand implements Command {
    //could also be set in a constructor instead
    List<Command> commandChain = Arrays.asList( new ScrapperCommand(),
                                            new ApiCommand());


    public Result handle( Request request){

         Result result = null;
         Iterator<Command> iter = commandChain.iterator();
         while( result ==null && iter.hasNext()){
              result = iter.next().handle(request);
         }

         return result;
    }
}

【讨论】:

    【解决方案2】:

    人们建议使用chain of responsibility 模式,但是当我想到我遇到的问题时,我可以使用Command 模式的变体来解决这个问题。它是这样工作的。

    将每个if 语句替换为实现Command 接口的相应类。在我们的示例中,我将实现类ScreenScrapeTextCommandFetchTextFromAPICommand。由于每个类都将实现Command 接口,我们将为每个类添加execute() 方法(该方法实际上将执行我们需要的功能,例如屏幕抓取或从API 获取)。

    然后我们将创建一个包含所有相关命令的新类。我们称这个类为GetTextCommandCenter。该类将包含Commands 中的list,格式为public List&lt;Command&gt; commandList;,然后我们将通过以下方式将前两个类添加到列表中来硬编码命令:

    commandList.add(new ScreenScrapeTextCommand();
    commandList.add(new FetchTextFromAPICommand();
    

    然后我们可以将if\else 链替换为以下内容:

    public String replaceIfElseWithCommand()..
    
    String text = null;
    int commandIndex = 0;
    
    while (text == null && text == someCondition)
    {
    
    text = new GetTextCommandCenter().commandList(commandIndex).execute();
    commandIndex++;
    }
    
    return text;
    
    }
    

    一旦命令成功,while 循环中的条件将失败,方法将相应返回。

    这样,我们可以通过向CommandCenter 类添加更多类或快速更改单个命令的优先级来轻松添加更多命令。

    我认为这是对我的问题的简单直接的解决方案(但如果您认为chain of responsibility 模式更合适以及您为什么这么认为,请发表评论)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-02
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      相关资源
      最近更新 更多