1
개체가 reify
으로 만들어졌으며 해당 메서드 중 하나를 재정의해야합니다. 내가 찾은 유일한 방법은 reify
을 다른 용도로 사용하여 고전적인 OO 데코레이터를 사용하는 것입니다. 다른 방법이 있습니까?기존 개체의 메서드를 재정의하는 방법은 무엇입니까?
개체가 reify
으로 만들어졌으며 해당 메서드 중 하나를 재정의해야합니다. 내가 찾은 유일한 방법은 reify
을 다른 용도로 사용하여 고전적인 OO 데코레이터를 사용하는 것입니다. 다른 방법이 있습니까?기존 개체의 메서드를 재정의하는 방법은 무엇입니까?
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 [[email protected]]
(. ~proto-name (~name [email protected]))) ;; this is where we delegate to the prototype
)))]
`(let [~proto-name ~proto]
(proxy
[~clazz] []
[email protected](->> method-bodies (group-by first) (sort-by first)
(map (fn [[name bodies]]
`(~name [email protected](for [[name & rest] bodies]
rest))))))
)))
당신은 그것을 사용하는 것이 방법 :
(decorator
java.util.Collection
[:a :b :c]
(size [] -1))
=> #object[user.proxy$java.lang.Object$Collection$4e41253d
0x1eae8922
"[email protected]"]
그리고 확장 :
(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
.
감사합니다. 총 3 가지 메소드를 가진 단 하나의 객체 일 뿐이므로 두 개의 프로토콜 (한 프로토콜에서 2 개의 메소드와 다른 프로토콜에서 2 개의 메소드)을 구현하므로 매크로가 없어도 나쁘지 않습니다. 난 그냥 핵심 Clojure lib에서 아무것도 놓치지 않고 있는지 확인 싶었어요. 나는 메소드의 수가 더 많았다면 확실히 매크로로 갈 것이다. 개체는 외부 라이브러리에서 만들어 지므로이 개체를 약간 사용자 지정해야합니다. – Pol