我使用綁定有兩個原因:
- 使用「全局」的資源,例如數據庫連接或消息中介通道運行重寫常量或其他符號的其它值測試
testing
我工作在一個分佈式系統上有幾個組件通過消息交換髮送消息進行通信。這些交換機具有全局名稱,這是我喜歡這樣的定義:
(ns const)
(def JOB-EXCHANGE "my.job.xchg")
(def CRUNCH-EXCHANGE "my.crunch.xchg")
;; ... more constants
這些常量在許多地方被用來將消息發送到正確的地方。爲了測試我的代碼,我的測試套件的一部分運行使用實際消息交換的代碼。但是,我不希望我的測試干擾實際系統。
爲了解決這個問題,我總結我的測試代碼的binding
呼叫覆蓋這些常量:
;; in my testing code:
(binding [const/CRUNCH-EXCHANGE (str const/CRUNCH-EXCHANGE (gensym "-TEST-"))
const/CRUNCH-TASK-QUEUE (str const/CRUNCH-TASK-QUEUE (gensym "-TEST-"))]
;; tests here
)
這裏面binding
功能,我可以調用使用常數的任何代碼,它會使用重寫的值。
使用全球資源
另一種方式我使用綁定是「修復」特定範圍內的全球或單資源的價值。這裏有一個RabbitMQ的庫我寫的,我在那裏一個RabbitMQ的Connection
的值綁定到符號*amqp-connection*
的例子讓我的代碼可以使用它:
(with-connection (make-connection opts)
;; code that uses a RabbitMQ connection
)
的with-connection
實現相當簡單:
(def ^{:dynamic true} *amqp-connection* nil)
(defmacro with-connection
"Binds connection to a value you can retrieve
with (current-connection) within body."
[conn & body]
`(binding [*amqp-connection* ~conn]
[email protected]))
我的RabbitMQ庫中的任何代碼都可以使用*amqp-connection*
中的連接,並假定它是有效的,打開Connection
。或者使用(current-connection)
功能,它拋出,當你忘記在with-connection
來包裝你的RabbitMQ調用一個描述異常:
(defn current-connection
"If used within (with-connection conn ...),
returns the currently bound connection."
[]
(if (current-connection?)
*amqp-connection*
(throw (RuntimeException.
"No current connection. Use (with-connection conn ...) to bind a connection."))))
給大家,到目前爲止都是很好的答案。如果有其他人想要刺傷,我會在選擇一個答案之前多留幾天。 – bmillare