Clojure:高阶函数 vs 协议 vs 多方法

4
有许多协议与多方法的比较,但为什么不使用高阶函数呢?看一个例子:我们有一些数据(例如记录),还有方法 serialize deserialize 。假设我们想将它保存到文件中,保存为json格式,并保存到数据库中。我们应该创建名为 SerializationMethod 的协议以及实现它们的记录称为 database json ,< strong> file 吗?这似乎有点繁琐,因为只是为了使用协议而创建记录。第二种解决方案-多方法可能需要带有序列化输出的字符串参数,并决定如何执行此操作。但我不确定这是正确的方法...第三种方法是编写函数 serialize ,然后传递数据和序列化函数。但现在我无法使用相同的名称命名序列化和反序列化方法(例如json):
(defn serialize [method data]
  (method data))

(defn json[data]
  (...))

问题是我应该如何做到这一点。有没有更通用的高阶函数?或者是我对某些东西的理解不够深入? 这是我在clojure中的第一步,请多包容。
1个回答

2

将数据转换为JSON与写入数据库或文件不同,后者是IO操作,而前者是纯粹的数据转换。考虑到这一点,我不建议在同一个接口下实现它们。

现在假设您有各种序列化实现,比如json和fressian,那么在每个要(反)序列化的数据结构上实现它们肯定不是一个好主意。您正确地观察到,这将是一种hack。更简洁地说,这将限制记录只能使用一种实现进行(反)序列化。

相反,更有效的方法是拥有不同的序列化程序,每个程序都实现相同的接口:

(defrecord JSONSerializer []
  SerializationMethod
  (serialize [this data] ...)
  (deserialize [this data] ...))

(defrecord FressianSerializer []
  SerializationMethod
  ...)

这样我们最终会有多个序列化器对象,可以传递给需要它们的函数。这些函数不必关心实现细节。

是否可以传递高阶函数来代替?

(defn do-something 
  [params serialize deserialize]
  ...)

这也是可行的。但请注意,这种风格很容易失控。例如,考虑需要编写一个函数的情况,该函数应将数据从一种格式反序列化并序列化到另一种格式。


关于区分JSON和写入数据库/文件,我完全同意。但是对于没有字段的记录创建记录的解决方案对我来说有点不正规。每次我们想要(反)序列化数据时,都需要创建一个记录实例(.serialize -> JSONSerializer data)。至于HOF,我的意思是:(序列化JsonSerialization data)。以及序列化和反序列化:(序列化FressianSerialization(反序列化JsonDeserialization data))或使用箭头宏。 - ravenwing
我为了举例省略了一些字段。拥有包含配置参数的字段是有很好的理由的。您不必每次调用SerializationMethod协议的方法时都创建一个JSONSerializer。如果实现正确,一个记录的方法可以被多次调用 - 如果实现了线程安全,甚至可以从不同的线程中调用。您评论中的HOF示例没有传递函数(???)-- - Leon Grapenthin
JsonSerialization 是一个函数,也有 FressianSerialization。但现在我看到这个解决方案多么愚蠢 - 它甚至不值得称为解决方案。 - ravenwing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接