用状态/策略模式替换if / else逻辑

时间:2014-10-26 08:57:25

标签: java if-statement state strategy-pattern

我已经阅读过以前的堆栈交换,用Java替换条件逻辑,例如带有状态/策略模式的IF / ELSE,但我不确定我的情况是否适合替换。 我看了一下 - Long list of if statements in JavaConverting many 'if else' statements to a cleaner approach

我基本上是在编写一个文件下载管理器,这些是我的IF / ELSE结构:

  1. 如果文件及其zip文件存在,则将zip文件移至zip文件目录并读入文件
  2. 如果zip文件存在,则解压缩文件并将zip文件移至zip文件目录并读入文件
  3. 如果zip文件不存在,请从指定的URL下载 然后解压缩并读入文件并将zip文件移动到指定目录。
  4. 如果URL中不存在zip文件,则创建空白文件并将其写入磁盘。
  5. 基本上我理解你将这四个条件作为哈希映射中的键,然后值是需要发出的“命令”。 但是我相信你仍然需要一个If / Else来决定在作为输入给出的键上调用什么动作。所以我没有看到好处。有人可以解释一下吗?

2 个答案:

答案 0 :(得分:4)

我认为你应该使用GoF模式Chain of responsibility。您应该引入两个接口:1)Condition您将在其中检查正确的条件,例如"如果zip文件不存在"并返回布尔结果 - " true"如果条件满足,否则"否则",2)Execution strategy,将运行分配有条件的动作,例如"从指定的URL下载它,然后解压缩并读入文件并将zip文件移动到指定的目录。"因此,第一个界面将回答问题"当"和第二个 - "然后"。 "条件"实施和执行战略"实施应该合并到"元组" (或配对,进入等)。这个"元组"应该按顺序移动到收集,你已经描述过了。然后,当你需要处理zip文件时,你将迭代收集,调用条件和检查结果,如果结果是" true"然后调用适当的"执行策略"。此外,条件可以与执行策略结合,并通过两种方法转移到单个接口/实现中。上下文,将描述zip文件的当前状态,可以在条件/执行策略之间传递。 希望这会有所帮助。

<强>更新 代码示例(在Java中)。

/**
 * All implementations should check proper condition
 */
interface Condition { 

  /**
   * Check if condition is satisfied
   *
   * @param pathToFile path to target file
   * @return 'true' if condition is satisfied, otherwise 'false'
   */
  boolean isSatisfied(String pathToFile); //i've made an assumption that you'll manipulate file path for checking file
}
...
/**
 * Childs will wrap some portion of code (if you'll use language, that supports lambdas/functors, this interface/implementation can be replaced with lambda/functor)
 */
interface Action {

  /**
   * Execute some portion of code
   *
   * @param pathToFile path to target file
   */ 
  void execute(String pathToFile);
}
...
class ZipFileExistsCondition implements Condition {

  @Override
  public boolean isSatisfied(String pathToFile) {
   ... //check if zip file exists
  }
}
...
class ZipFileDoesNotExists implements Condition {
  @Override
  public boolean isSatisfied(String pathToFile) {
   ... //download zip file and move it to some temp directory
   //if file downloaded ok, than return 'true' otherwise 'false'
  }
}
...
class AlwaysSatisfiedCondition implements Condition {
  @Override
  public boolean isSatisfied(String pathToFile) {
   ... //always returns 'true', to run action assigned with this condition
  }
}
...
Collection<Map.Entry<Condition, Action>> steps = Arrays.asList(
 new AbstractMap.ImmutableEntry<Condition, Action>(new ZipFileExistsCondition(), 
 new Action() { /*move zip file to zip file directory and read in file*/ }),
 new ZipFileDoesNotExists(), new Action() { /*download it from specified URL and then unzip it and read in file and move zip file to specified directory*/ },
 new AlwaysSatisfiedCondition(), new Action() { /*create blank file and write it out to disk*/  }
);
...
String pathToFile = ...
...
for(Map.Entry<Condition, Action> step: steps) {
 if(!step.getKey().isSatisfied(pathToFile))
   continue;

 step.getValue().execute(pathToFile); 
}  

说明: 1)你可以实施条件&#39;作为匿名课程, 2)&#39; AlwaysSatisfiedCondition&#39;可以是单身, 3)如果你正在使用Java / Groovy / Scala,你可以使用Guava / Apache Commons&#39; Predicate&#39;而不是条件&#39;,&#39;功能&#39;或者&#39;关闭&#39;而不是&#39;行动&#39;。

如果您需要在第一次满意后退出&#39;条件和适当的行动执行,然后只是把'休息&#39; /&#39;返回&#39;行动执行后。

答案 1 :(得分:2)

以下是编译此代码的正确方法。这里的关键点是AbstractMap.SimpleImmutableEntry是一个单独的条目。如果要添加更多条目,则需要为每个条目实例化类。

Collection<Map.Entry<Condition,Action>> steps = Arrays.asList
    (
     (new AbstractMap.SimpleImmutableEntry<Condition,Action>
      (new FileExistsCondition(),
       new Action()
       {
       public void execute(String pathToFile){System.out.println("the path to file is srtm " + pathToFile);}
      }
       )
      ),
     (new AbstractMap.SimpleImmutableEntry<Condition,Action>
      (new ZipFileExistsCondition(),
       new Action()
       {
       public void execute(String pathToFile){System.out.println("the path to file is  " + pathToFile);}
      }
       )
      ),
     (new AbstractMap.SimpleImmutableEntry<Condition,Action>
      (new ZipFileDoesNotExistCondition(),
       new Action()
       {
       public void execute(String pathToFile){System.out.println("the path to file is " + pathToFile);}
      }
      )
      )
     );