### Watchers
WARNING: 下面這個章節要做一些更新,因為在Clojure1.1里面 `add-watcher` 和 `remove-watcher` 這兩個函數被去掉了。 兩個不大一樣的函數 `add-watch` 和 `remove-watch` 被添加進來了。
Agents 可以用作其它幾種引用類型的監視器。當一個被監視的引用的值發生了改變之后,Clojure會通過給Agent發送一個action的形式通知它。通知的類型可以是 `send` 或者 `send-off` , 這個是在你把Agent注冊為引用類型的監視器的時候指定的。那個action的參數是那個監視器 Agent 以及發生改變的引用對象。這個action的返回值則是Agent的新值。
就像我們前面已經說過的那樣,函數式編程強調那種“純函數” -- 不會改變什么全局變量的函數。但是Clojure也不絕對靜止這樣做, 但是Clojure使得我們要找出對全局狀態進行了改變的函數非常的簡單。一個方法就是尋找那些能對狀態進行改變的宏和方法,比如 `alter` 。 這到了調用這些宏/函數的地方就找到了所有修改全局狀態的地方了。另外一個方法就是用Agent來監視對于全局狀態的更改。一個監視者可以通過dump出來stack trace來確定到底是誰對全局狀態做了修改。
下面的例子給一個Var,一個Ref, 一個Atom注冊了一個Agent監視者。Agent里面維護了它所監視的每個引用被修改的次數(一個map)。這個map的key就是引用對象,而值則是被修改的次數。
```
(def my-watcher (agent {}))
(defn my-watcher-action [current-value reference]
(let [change-count-map current-value
old-count (change-count-map reference)
new-count (if old-count (inc old-count) 1)]
; Return an updated map of change counts
; that will become the new value of the Agent.
(assoc change-count-map reference new-count)))
(def my-var "v1")
(def my-ref (ref "r1"))
(def my-atom (atom "a1"))
(add-watcher (var my-var) :send-off my-watcher my-watcher-action)
(add-watcher my-ref :send-off my-watcher my-watcher-action)
(add-watcher my-atom :send-off my-watcher my-watcher-action)
; Change the root binding of the Var in two ways.
(def my-var "v2")
(alter-var-root (var my-var) (fn [curr-val] "v3"))
; Change the Ref in two ways.
(dosync
; The next line only changes the in-transaction value
; so the watcher isn't notified.
(ref-set my-ref "r2")
; When the transaction commits, the watcher is
; notified of one change this Ref ... the last one.
(ref-set my-ref "r3"))
(dosync
(alter my-ref (fn [_] "r4"))) ; And now one more.
; Change the Atom in two ways.
(reset! my-atom "a2")
(compare-and-set! my-atom @my-atom "a3")
; Wait for all the actions sent to the watcher Agent to complete.
(await my-watcher)
; Output the number of changes to
; each reference object that was watched.
(let [change-count-map @my-watcher]
(println "my-var changes =" (change-count-map (var my-var))) ; -> 2
(println "my-ref changes =" (change-count-map my-ref)) ; -> 2
(println "my-atom changes =" (change-count-map my-atom))) ; -> 2
(shutdown-agents)
```