草庐IT

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

coder 2024-03-19 原文

我已经阅读了之前关于用状态/策略模式替换 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 文件,则创建空白文件并将其写入磁盘。

基本上,据我了解,您将这四个条件作为键放在散列映射中,然后值是需要发出的“命令”。 但是我相信您仍然需要一个 If/Else 来决定对作为输入给出的键调用什么操作。所以我看不到好处。有人可以解释一下吗?

最佳答案

我认为你应该使用 GoF 模式 Chain of responsibility .您应该引入两个接口(interface):1) Condition 您将在其中检查适当的条件,例如“如果 zip 文件不存在”并返回 boolean 结果 - 如果满足条件则为“true”,否则为“else”,2) Execution strategy,将运行指定条件的操作,例如“从指定的 URL 下载它然后解压缩并读入文件并将 zip 文件移动到指定的目录。”因此,第一个界面将回答“何时”问题,第二个界面将回答“然后”问题。 “条件”实现和“执行策略”实现应该组合成“元组”(或对、条目等)。这个“元组”应该按您所描述的顺序移动到集合中。然后,当您需要处理 zip 文件时,您将遍历集合、调用条件并检查结果,如果结果为“真”,则调用适当的“执行策略”。此外,条件可以与执行策略相结合,并使用两种方法移动到单一接口(interface)/实现中。描述 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)您可以将“条件”实现为匿名类, 2) 'AlwaysSatisfiedCondition' 可以是单例, 3) 如果您使用的是 Java/Groovy/Scala,则可以使用 Guava/Apache Commons“Predicate”代替“Condition”、“Function”或“Closure”代替“Action”。

如果您需要在第一个“满足”条件和适当的操作执行后退出,那么只需在操作执行后放置“break”/“return”。

关于java - 用状态/策略模式替换 if/else 逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26571351/

有关java - 用状态/策略模式替换 if/else 逻辑的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  8. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  9. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  10. ruby - ruby 中有 each_if 吗? - 2

    假设我在Ruby中有这个each循环。@list.each{|i|putsiifi>10breakend}我想循环遍历列表直到满足条件。这让我感到“不像Ruby”,因为我是Ruby的新手,是否有Ruby方法可以做到这一点? 最佳答案 您可以使用Enumerable#detect或Enumerable#take_while,取决于您想要的结果。@list.detect{|i|putsii>10}#Returnsthefirstelementgreaterthan10,ornil.正如其他人所指出的,更好的风格是先进行子选择,然后再对其

随机推荐