通常当我在库中看到clojure协议时,协议方法将被包装在一个函数中,通常几乎没有添加任何功能。 e.g:
(defprotocol Pfoo
(foo-method [this]))
(deftype Atype [x y]
Pfoo
(foo-method [this] (do-something)))
(defn foo [arg] (foo-method arg))
通常希望客户端调用函数foo,而不是协议中的foo方法。 (有关此类事件的具体示例,请参阅clojurescript core顶部的协议。
那么为什么协议经常被屏蔽功能呢?无法将协议方法变成面向客户端的部分,而不是包装函数吗?
答案 0 :(得分:22)
协议代表两种具体实体之间的接口点。一个是调用协议的代码(在您的示例中调用foo
的任何内容),另一个是实现它的代码(Atype
foo-method
)。方便一个人可能不方便另一个。实现者希望提供最完整的最小接口,而呼叫者需要可支持的最丰富的API。
你提到过ClojureScript核心;看看那里的ISeq
协议。它由几种类型实现,每种类型都必须实现-first
和-rest
。为了使这些实现尽可能简单,不需要在其arg上调用seq。但是,面向调用者的相关函数first
和rest
支持传递非seqs,如字符串,向量等,因此这种常见功能由非协议函数提供。当然调用者 - 面对API比next
,map
,filter
,顺序解构等更加丰富,所有这些都建立在-first
和-rest
之上。
包装协议方法的fns提供的其他常见功能包括参数验证(如断言),默认参数和对var-args的支持。