2012-11-27 27 views
5

我有一種情況,我在一個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) 

第二個命名空間

(ns scratch-clj.another) 


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

這裏的問題是,劃痕clj.first有需要再和明確推送移除事件。這有點笨重,但是如果我有另一個「另一個」命名空間,它也想工作,這也是行不通的。

因此,我想到了鉤住第一個功能。

+0

嗯,要小心術語「破壞」。我相信物體的破壞只發生在GC清理之後。刪除對象與銷燬對象不同,但可能會導致另一個對象。 –

回答

1

這是解決方案適合您的要求?

刮擦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)) 

一些聽衆:

(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)) 

初始化結合:

(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)) 

測試:

(test-it) 
=> object added is: #<Object [email protected]> 
    [#<Object [email protected]>] 
    object removed is: #<Object [email protected]> 
    () 
+0

是的,我認爲它的確如此。我想我也可以用手錶來做到這一點,但這對我來說似乎更自然一些,也更普遍。非常感謝! –

+0

不客氣。但它仍然沒有標記爲正確:( – mobyte

1

聽起來很像你描述的是回調。

喜歡的東西:

(defn make-object 
    [destructor-fn] 
    {:destructor destructor-fn :other-data "data"}) 

(defn destroy-object 
    [obj] 
    ((:destructor obj) obj)) 

; somewhere at the calling code... 

user> (defn my-callback [o] (pr [:destroying o])) 
#'user/my-callback 
user> (destroy-object (make-object my-callback)) 
[:destroying {:destructor #<user$my_callback [email protected]>, :other-data "data"}] 
nil 
user> 
+0

這是一個合理的想法,但它只是改變了問題。現在我需要能夠鉤入我的make-object函數,所以我可以添加一個析構函數。以上面的例子(在你的評論後添加,對不起!) - 對象創建和銷燬發生在名字空間「第一」,而我的回調等價物在其他地方。 –

+0

好吧,這樣說,其中一個問題就是clojure並沒有真正發揮出那些具有析構函數的對象的想法。如果您將(幾乎)所有對象視爲「啞」記錄,則通常會有更好的時間。從你的代碼中你不想看到對象是否被銷燬,你想在listf中的集合被修改時做任何動作。手錶是這個明顯的工具,他們不可能很快被刪除。 –

+0

在這種情況下,有問題的對象(如我的示例中)是Java對象 - 我正在使用clojure來操作Java API。一旦從列表中刪除,對象將被銷燬。參考手錶保證被稱爲?這不是可否否決? –

0

所以,這是我的最終解決方案,遵循mobytes的建議。多一點工作,但 我懷疑我將來想要這個。

感謝所有幫助

;; hook system 
(defn make-hook [] 
    (atom [])) 

(defn add-hook [hook func] 
    (do 
    (when-not 
     (some #{func} @hook) 
     (swap! hook conj func)) 
    @hook)) 

(defn remove-hook [hook func] 
    (swap! hook 
     (partial 
      remove #{func}))) 

(defn clear-hook [hook] 
    (reset! hook [])) 

(defn run-hook 
    ([hook] 
     (doseq [func @hook] (func))) 
    ([hook & rest] 
     (doseq [func @hook] (apply func rest)))) 

(defn phils-hook [] 
    (println "Phils hook")) 

(defn phils-hook2 [] 
    (println "Phils hook2")) 


(def test-hook (make-hook)) 
(add-hook test-hook phils-hook) 
(add-hook test-hook phils-hook2) 
(run-hook test-hook) 
(remove-hook test-hook phils-hook) 
(run-hook test-hook)