簡體   English   中英

"如何覆蓋現有對象的方法?"

[英]How to override a method of an existing object?

該對象是用reify<\/code>創建的,我需要重寫它的一種方法。 我發現的唯一方法是使用經典的 OO 裝飾器和reify<\/code>的另一種用法。 還有其他方法嗎?

"

恐怕您必須制作一個裝飾器,因為 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來完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM