【问题标题】:Why the Execute Aroud idiom is not considered a Strategy design pattern?为什么 Execute Aroud 习语不被视为一种策略设计模式?
【发布时间】:2023-04-06 18:44:01
【问题描述】:

我越来越多地看到相同解决方案的新标签,但名称不同。在这种情况下,为什么我们不能简单地说 Execute Aroud 成语与 Strategy design pattern 相同?

当我阅读Jon Skeet’s answer 的问题时:“什么是“执行周围”成语?”,他说:

这是您编写方法来做总是需要的事情的模式,例如资源分配和清理,并让调用者传入“我们想对资源做什么”。

在这种情况下,@jon-skeet 使用 executeWithFile(String filename, InputStreamAction action) 方法作为 执行始终需要的事情的方法示例,并使用接口 InputStreamAction 作为对 what 的抽象我们想要处理资源

  public interface InputStreamAction
  {
      void useStream(InputStream stream) throws IOException;
  }

将此与Stratey design pattern 进行比较,为什么我们不能只说接口InputStreamAction 定义了一系列算法?并且,接口InputStreamAction 的每个实现都对应一个封装算法的具体策略。最后,这些算法是可以互换的,我们可以将executeWithFile 与任何这些策略一起使用。

那么,我为什么不能把Jon Skeet’s answer解释为Stratey design pattern的应用例子呢?

顺便问一下,哪个成语最先出现? Execute Around 还是 Strategy 设计模式?

虽然 Execute Around 习语通常与函数式编程有关,但我发现的唯一文档是在 1997 年的 Smalltalk Best Practice Patterns 书中,属于 Smalltalk 编程语言的范围,它遵循 OO 方法。

因为设计模式描述了一般解决方案来解决经常出现的问题,那么我们可以说执行周围和策略都是相同的解决方案解决不同的问题。所以,我问:我们真的需要不同的名称来识别相同的解决方案,当它应用于不同的问题时?

虽然我同意@iluwatar 的answer 这是传达不同想法的方式,但我仍然认为我可以传达 Execute Around 的想法,只是告诉它:“我使用了一个指定我想对资源做什么的策略,始终以相同的方式设置和清理。”

所以 Execute Around 成语减少了歧义(这很好),但同时也增加了设计模式的名称?而且,这是一个好习惯吗?

【问题讨论】:

    标签: java oop design-patterns language-agnostic idioms


    【解决方案1】:

    虽然Strategy 和 Execute Around 在技术上非常相似,但它们传达了不同的想法。当我们讨论可互换算法时,使用的术语是Strategy。当我们讨论围绕业务方法分配和释放资源时,我们应该使用术语 Execute Around。

    【讨论】:

    • 我不认为这种比较类似于状态与策略模式之间的辩论。首先,状态和策略都是 [Eric Gamma 等人](en.wikipedia.org/wiki/Design_Patterns) 书中包含的有据可查的设计模式。执行周围没有记录。其次,上下文通过具体的 Strategy 提供完整的功能,例如 Execute Around,它通过具体的 Action 提供完整的功能。另一方面,在状态设计模式中,上下文依赖于几个具体的状态。
    • 恕我直言,Execute Around 习惯用法是对我们模式的一个很好且有用的补充。我的主要观点是,当设计师讨论代码结构时,Execute Around 传达的东西与 Strategy 完全不同,这很有用。
    • 好的,我同意您的观点,即“执行周围传达与战略完全不同的东西”。从语义的角度来看,它们在不同的上下文中使用。关于一个设计模式由几个属性描述,包括:名称、分类、目标、结构等,还有一个上下文,让程序员可以识别他们在哪里的问题可以应用某种设计模式。从这个意义上说,尽管 Execute Around 和 Strategy 共享一个具有相同结构的解决方案,但它们适用于不同的上下文
    • 然而,我仍然不同意你与围绕状态与战略的辩论的比较。在状态模式中,上下文依赖于几个具体的状态,而在策略中,上下文只依赖于一个具体的策略。此外,在策略模式中,客户端可以提供上下文未知的具体策略,而在状态模式中,上下文可能事先知道具体状态。因此,我建议您从答案中删除对国家的提及。而且,也许你可以用每个模式传达的内容来完成你的答案。
    • 感谢您的建议。我根据你的 cmets 编辑了答案。
    【解决方案2】:

    对我来说,作为“算法家族”的策略模式意味着有多种不同的方法可以实现特定目标。例如,有多种不同的算法/策略可以实现对值列表进行排序的特定目标。但在给出的示例中——executeWithFile 处理文件的打开和关闭——我认为InputStreamAction 系列没有任何特定目标。具体的实现可能都有不同的目标。

    在 Java 中,Execute Around 模式需要作为接口具体实现的对象。我认为这就是它看起来与策略模式如此相似的原因。但在其他语言中,只需要一个普通的旧函数。以 Ruby 为例:

    execute_with_file('whatever.txt') do |stream|
       stream.write('whatever')
    end
    

    没有InputStreamAction接口,也没有具体的WhateverWriterAction。只有一个函数将另一个函数作为参数。可以将普通的旧函数参数视为“策略”吗?可能是,但我不会称其为策略。当我使用或创建 Execute Around 实现时,我当然不会从策略模式的角度来考虑它。

    总而言之,如果你想非常直白,你可以说 Execute Around 是一种特定类型的策略模式。但是,如果您考虑这两种模式背后的意图,它们是不同的想法:策略模式是实现特定目标的一系列算法,而 Execute Around 是在一段任意代码之前和之后运行某些东西的通用方式。

    【讨论】:

    • 请注意,从 Java 8 开始,您还可以将函数作为参数传递给其他函数。
    • 这是一个非常有趣的观察,有助于理解这两个术语的存在。你是说 Execute Around 的起源来自函数式语言吗? (与 oop 领域众所周知的 Strategy 相反)您能否提供有关 Execute Around 成语/模式的参考?
    • 我不确定,但 Execute Around 来自具有一流功能的语言听起来很合理。这是用这些语言编写代码的一种非常自然的方式。如此自然,事实上,即使我确切地知道它是什么,在我阅读你的问题之前我从未真正听说过它的名字,所以我真的无法为你指出任何比谷歌更好的参考资料。
    • 我也不确定这是否是关于 Execute Around 习语的第一个文档,但我从 1997 年在 Smalltalk 的面向对象范围内的这本书中找到了它:books.google.pt/books/about/…
    【解决方案3】:

    在我看来,虽然两者都可能是类似问题的解决方案,但它们是不同的习语,因此应该有不同的名称。

    我称它们为惯用语,因为它周围的执行只是一个programming idiom,用于许多典型情况(类似于所介绍的情况)以及多种语言。而且,至少据我所知,Execute Around 从未正式成为一种软件设计模式,至少目前如此。

    为什么它们不同?这是我的看法:
    Stategy 设计模式旨在(来自维基百科):

    • 定义了一系列算法,
    • 封装了每个算法,并且
    • 使算法在该系列中可互换。

    通常将 strategy 实例作为与上下文实例的长期关系,通常作为构造函数依赖项传递。即使上下文可能有策略的设置器,相同的策略可以在多次调用上下文中使用,而调用者(客户端)甚至不知道该特定上下文正在使用哪个策略,并且此刻通话结束。此外,上下文可以在其公共接口的多个方法中使用相同的策略实例,而调用者甚至不知道它的用法。

    另一方面,idiom 周围的执行适用于参数化算法,其中调用者(客户端)应始终在每次调用中传递算法参数化函数。因此,传递的 strategy 函数只影响该特定调用的行为,而不影响其他调用。

    尽管所呈现的差异可能会在理论上和修辞上相结合,但如果您将被调用的上下文置于多线程场景中,我认为差异会更明显、更容易看到和“感受到”。

    如果没有大量的锁和同步,你就不能在多线程场景中使用策略设计模式,至少在允许改变上下文策略的情况下是这样。如果你不这样做,你会看到上下文和策略之间的这种关系的持续时间更长,因为它们通常同时存在。

    如果执行得当,execute around 习语应该不会患上这种“疾病”,至少如果传递的函数没有任何副作用的话。

    总结一下,虽然 Strategy 设计模式和 execute around 习语可能有相似之处,但可能用于解决类似的问题,并且可能有相似的静态结构,它们本质上是不同的,前者更多的是面向对象的风格,后者更多的是功能风格,因此应该有不同的名称!

    我同意 Miguel Gamboa 的观点,即泛滥的具有相同含义的名称是不好的,应该避免。但是,至少在我看来,情况并非如此。

    希望这会有所帮助!

    【讨论】:

    • 我认为你把这两个成语的主要区别说得很清楚了。现在我认为我的误解来自这样一个事实,即一些作者将策略设计模式与不是真正策略的东西联系起来,例如方法 filter:List<T> filter(List<T> itens, Predicate<T> p) 在 [ Java 8 in Action](github.com/java8/Java8InAction) 与策略设计模式相关。而且,根据您的观点,这不是策略设计模式的应用。
    猜你喜欢
    • 1970-01-01
    • 2010-12-12
    • 2014-10-18
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 2016-06-14
    • 1970-01-01
    相关资源
    最近更新 更多