该对象是用以下命令创建的reify
我需要重写它的方法之一。我发现的唯一方法是使用经典的 OO 装饰器和另一种用途reify
。还有其他办法吗?
恐怕你必须创建一个装饰器,因为 Clojure 没有内置构造来默认将一个对象的行为委托给另一个对象(我认为这称为原型继承)。
但这并不意味着它必须很乏味 - 您可以使用宏和反射来自动化大部分工作。这是概念证明:
(defmacro decorator
[clazz proto & fs]
(let [proto-name (gensym "proto")
methods (->> (clojure.reflect/reflect (resolve clazz))
:members
(filter #(instance? clojure.reflect.Method %))
(map (fn [{:keys [name parameter-types]}]
[name (count parameter-types)]))
set)
to-delegate (clojure.set/difference
methods
(->> fs
(map (fn [[name params]]
[name (count params)]))
set))
method-bodies
(concat
fs ;; these are our own definitions
(for [[name n-params] to-delegate]
(let [params (->> (range n-params)
(map #(gensym (str "x" %))))]
`(~name [~@params]
(. ~proto-name (~name ~@params))) ;; this is where we delegate to the prototype
)))]
`(let [~proto-name ~proto]
(proxy
[~clazz] []
~@(->> method-bodies (group-by first) (sort-by first)
(map (fn [[name bodies]]
`(~name ~@(for [[name & rest] bodies]
rest))))))
)))
您将如何使用它:
(decorator
java.util.Collection
[:a :b :c]
(size [] -1))
=> #object[user.proxy$java.lang.Object$Collection$4e41253d
0x1eae8922
"user.proxy$java.lang.Object$Collection$4e41253d@6abe9887"]
以及扩展:
(macroexpand-1 '(decorator
java.util.Collection
[:a :b :c]
(size [] -1)))
=>
(clojure.core/let
[proto28109 [:a :b :c]]
(clojure.core/proxy
[java.util.Collection]
[]
(add ([x028114] (. proto28109 (add x028114))))
(addAll ([x028110] (. proto28109 (addAll x028110))))
(clear ([] (. proto28109 (clear))))
(contains ([x028118] (. proto28109 (contains x028118))))
(containsAll ([x028116] (. proto28109 (containsAll x028116))))
(equals ([x028119] (. proto28109 (equals x028119))))
(hashCode ([] (. proto28109 (hashCode))))
(isEmpty ([] (. proto28109 (isEmpty))))
(iterator ([] (. proto28109 (iterator))))
(parallelStream ([] (. proto28109 (parallelStream))))
(remove ([x028117] (. proto28109 (remove x028117))))
(removeAll ([x028115] (. proto28109 (removeAll x028115))))
(removeIf ([x028111] (. proto28109 (removeIf x028111))))
(retainAll ([x028112] (. proto28109 (retainAll x028112))))
(size ([] -1))
(spliterator ([] (. proto28109 (spliterator))))
(stream ([] (. proto28109 (stream))))
(toArray ([] (. proto28109 (toArray))) ([x028113] (. proto28109 (toArray x028113))))))
该实现生成一个proxy
子句,但也可以用reify
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)