在 Clojure 中使用 multimethods 代替 cond 有什么好处?

Ask*_*ker 8 polymorphism clojure conditional-statements

为什么 Clojure 中的 multimethods 不能简单地替换为 cond 表达式?

在查看了 Ch 中多方法的简单示例后,我受到启发提出了问题。Russ Olsen 的《Getting Clojure》一书中的 5 篇。

在对类似问题(Clojure 中多方法与 cond 的性能)的回复中,用户 Daniel Compton 说

多方法允许开放扩展;其他人可以扩展您对任意表达式的多方法调度。Cond 表达式对其他人甚至您自己的代码的扩展是封闭的。

但是我完全不清楚在这种情况下“开放扩展”和“封闭扩展”是什么意思,因为在我看来,multimethods 和 cond 表达式都可以很容易地编辑或扩展。

那么......为什么不应该简单地用 cond 表达式替换 Clojure 中的多方法?

或者,等效地,如何或何时使用多方法比使用 cond 更好或更优雅?

cfr*_*ick 8

这里的关键点是“允许开放扩展”。任何人都可以为您的多方法添加新的分支——acond是硬编码的:新的调度必须添加到cond适当的代码中。

假设:您有一些小部件并且想要绘制它们。小部件有一个:type,您想draw在该类型上调度如何。

cond您所知道的所有小部件编写一个大文件会起作用。但是现在对于每个新小部件,您都必须触摸cond源代码并对其进行修改。这可以是完全的罚款,例如实际应用中,并不需要扩展。

对多方法做同样的事情任何人都可draw以为他们的小部件实现一个。因此,在编写代码时并不了解所有这些。这使它成为例如图书馆更好(甚至强制)的方法。

现在想象一下,你已经决定cond了你正在编写的库中的方法。任何一个新的widget现在必须自己写 draw,派出的第一个绘制,然后打电话给你的draw。此外,他们还必须确保,他们draw在任何地方都draw被调用,在那里你 被调用让它工作(这通常是不可能的)。

直接在 Clojure 核心中使用多方法的一个流行示例是 print-method. 通过这种方式,任何人都可以为他们的类型实现“序列化”并很好地发挥作用。

其他值得一看的例子是 clojure.testintegrant

  • `defmulti` 决定如何分派,如果您想参与,您的类型必须符合分派的完成方式。如果你必须改变方式,*dispatch* 完成,或者必须改变某种类型的操作,那么你当然必须触及原始代码。`cond` **决定并调度**,而 `defmulti` 仅提取 **如何**。 (3认同)
  • 举一个具体的例子,假设你的多方法的调度函数是`:type`。我可以为其添加一个新分支,而无需编辑调度函数:只需“(defmulti foo :mytype ...)”,然后使用“{:type :mytype :size 10}”等对象调用您的多方法。这就是 Clojure 打印功能的工作原理。 (3认同)
  • 这遵循[开放/封闭原则](https://en.wikipedia.org/wiki/Open%E2%80%93close_principle):_“软件实体(类、模块、函数等)应该开放以供扩展,但因修改而关闭”;也就是说,这样的实体可以允许在不修改其源代码的情况下扩展其行为。_ (2认同)