如何在Clojure中做钩子

Phi*_*ord 5 hook clojure

我有一种情况,我在一个clojure命名空间中创建和销毁对象,并希望另一个命名空间进行协调.但是我不希望第一个命名空间必须在对象销毁时显式调用第二个命名空间.

在Java中,我可以使用一个监听器.不幸的是,底层的java库不会发出对象破坏事件的信号.如果我在Emacs-Lisp中,那么我会使用钩子来实现这一目的.

现在,在clojure我不太确定.我找到了Robert Hooke库https://github.com/technomancy/robert-hooke.但这更像是elisp术语中的defadvice - 我正在编写函数.更多文档说:

"钩子意味着扩展你无法控制的功能;如果你拥有目标功能,显然有更好的方法来改变它的行为."

可悲的是,我发现它并不那么明显.

另一种可能性是使用add-watch,但这被标记为alpha.

我错过了另一个明显的解决方案

示例已添加:

首先命名空间......

(ns scratch-clj.first
   (:require [scratch-clj.another]))

(def listf (ref ()))

(defn add-object []
  (dosync
    (ref-set listf (conj
               @listf (Object.))))
  (println listf))


(defn remove-object []
  (scratch-clj.another/do-something-useful (first @listf))
  (dosync
     (ref-set listf (rest @listf)))
  (println listf))


(add-object)
(remove-object)
Run Code Online (Sandbox Code Playgroud)

第二名称空间

(ns scratch-clj.another)


(defn do-something-useful [object]
   (println "object removed is:" object))
Run Code Online (Sandbox Code Playgroud)

这里的问题是scratch-clj.first必须要求另一个并明确地推送删除事件.这有点笨拙,但如果我有"又一个"命名空间,也想听,也行不通.

因此我想到挂钩第一个功能.

mob*_*yte 2

该解决方案适合您的要求吗?

暂存-clj.first:

(ns scratch-clj.first)

(def listf (atom []))
(def destroy-listeners (atom []))
(def add-listeners (atom []))

(defn add-destroy-listener [f]
  (swap! destroy-listeners conj f))

(defn add-add-listener [f]
  (swap! add-listeners conj f))

(defn add-object []
  (let [o (Object.)]
   (doseq [f @add-listeners] (f o))
   (swap! listf conj o)
   (println @listf)))

(defn remove-object []
  (doseq [f @destroy-listeners] (f (first @listf)))
  (swap! listf rest)
  (println @listf))
Run Code Online (Sandbox Code Playgroud)

部分听众:

(ns scratch-clj.another
  (:require [scratch-clj.first :as fst]))

(defn do-something-useful-on-remove [object]
  (println "object removed is:" object))

(defn do-something-useful-on-add [object]
  (println "object added is:" object))
Run Code Online (Sandbox Code Playgroud)

初始化绑定:

(ns scratch-clj.testit
  (require [scratch-clj.another :as another]
           [scratch-clj.first :as fst]))

(defn add-listeners []
  (fst/add-destroy-listener another/do-something-useful-on-remove)
  (fst/add-add-listener another/do-something-useful-on-add))

(defn test-it []
  (add-listeners)
  (fst/add-object)
  (fst/remove-object))
Run Code Online (Sandbox Code Playgroud)

测试:

(test-it)
=> object added is: #<Object java.lang.Object@c7aaef>
   [#<Object java.lang.Object@c7aaef>]
   object removed is: #<Object java.lang.Object@c7aaef>
   ()
Run Code Online (Sandbox Code Playgroud)