【发布时间】:2015-08-23 20:28:54
【问题描述】:
我正在尝试扩展库 DomKM/silk。
具体来说,deftype Route 实现了协议 Pattern,它具有方法实现,我想在我的 Pattern 协议的自定义实现中重用它。
https://github.com/DomKM/silk/blob/master/src/domkm/silk.cljx#L355
(deftype Route [name pattern]
Pattern
(-match [this -url]
(when-let [params (match pattern (url -url))]
(assoc params ::name name ::pattern pattern)))
(-unmatch [this params]
(->> (dissoc params ::name ::pattern)
(unmatch pattern)
url))
(-match-validator [_]
map?)
(-unmatch-validators [_]
{}))
好的,所以我的实现看起来像这样,但我想“继承”Route 的方法。我的意思是先执行一些自定义逻辑,然后将其传递给原始的Route 方法。
(deftype MyRoute [name pattern]
silk/Pattern
(-match [this -url]
true) ;match logic here
(-unmatch [this {nm ::name :as params}]
true) ;unmatch logic here
(-match-validator [_] map?)
(-unmatch-validators [_] {}))
在 clojure / clojurescript 中这是如何完成的?
【问题讨论】:
-
Clojure 的设计者不喜欢方法的继承。我认为你不能以非常自然的方式做到这一点。您显然可以创建一个
Route对象并让MyRoute的方法委托给Route的方法。deftype创建的对象是 Java 类,因此您可以通过使用允许继承的两个 Java 互操作宏之一:proxy和gen-class来做您想做的事情。gen-class可能是矫枉过正,所以如果你走这条路,我建议proxy。但是,这违背了 Clojure 的设计目标,因此您可能只想简单地重新实现所需的代码。 -
Route中的函数并不大。如果你想经常这样做,你可以在deftype对象之外编写函数并使用Pattern方法调用它们。 -
@Mars 感谢您的回答!当我尝试使用代理时:
(proxy [Route] [name pattern] (-match []))我收到错误java.lang.VerifyError: Cannot inherit from final class。甚至可以在 deftype 上使用代理吗? -
也许不是。我不确定。我猜它不起作用并不让我感到惊讶。虽然它没有说你不能扩展 deftypes,但 Clojure 的 datatypes 页面的“数据类型和协议是自以为是的”部分会给你这个想法。 Clojure 旨在鼓励某些类型的编程,同时保留很大的灵活性。有时,在特定情况下,灵活性比人们想要的要少,但语言充满了权衡。
-
我最终使用了juxt/bidi。它更好地为可扩展性而设计。我已经为我的问题实现了优雅的解决方案。再次感谢
标签: clojure clojurescript