15

通常,当我在库中看到 clojure 协议时,协议方法将被包装在一个函数中,通常几乎没有添加功能。例如:

(defprotocol Pfoo
    (foo-method [this]))

(deftype Atype [x y]
    Pfoo
    (foo-method [this] (do-something)))

(defn foo [arg] (foo-method arg))

并且通常期望客户端调用函数 foo,而不是协议中的 foo 方法。(有关此类事情的具体示例,请参阅clojurescript 核心顶部的协议。

那么为什么协议经常被隐藏在函数后面呢?协议方法不能成为面向客户端的部分,而不是包装功能吗?

4

1 回答 1

23

协议代表两种具体实体之间的接口点。一个是调用协议的代码(foo在您的示例中调用的任何内容),另一个是实现它的代码(Atype foo-method)。对一个人方便的事情可能对另一个人不方便。实现者希望提供完整的最小接口,而调用者希望能够支持最丰富的 API。

您提到了 ClojureScript 核心;看看ISeq那里的协议。它由几种类型实现,每种类型都必须实现-first-rest。为了使这些尽可能容易实现,都不需要在其 arg 上调用 seq。但是,相关函数firstrest面向调用者支持传入非序列,如字符串、向量等,因此该通用功能由非协议函数提供。当然面向调用者的 API 比带有next, map,的 API 更丰富filter, 顺序解构等都建立在-firstand之上-rest

fns 提供的封装协议方法的其他常见功能包括参数验证(如断言)、默认参数和对 var-args 的支持。

于 2013-03-28T05:11:02.163 回答