2015-02-11 15 views
2

我將我的應用程序的一部分分成庫在clojure中的應用程序和庫之間的依賴注入

庫函數具有必須由應用程序注入的某些依賴項。我有一個協議爲藍本這個

(defprotocol MyLibDependencies 
    (some-injected-capability [x])) 

(defrecord Foo [y]) 
(defrecord Bar [y]) 

(defmulti render-response class) 

(defmethod render-response Foo [val] {:ok (some-injected-capability (:y val))}) 
(defmethod render-response Bar [val] {:err (some-injected-capability (:y val))}) 

,並在這裏的應用程序,我可以提供一個實現:

(extend-type Object 
    MyLibDependencies 
    (some-injected-capability [x] (inc x))) 

(comment 
    (render-response (Foo. 10)) ;; => {:ok 11} 
    (render-response (Bar. 10)) ;; => {:err 11} 
) 

這工作,但感覺就像協議的濫用,因爲我既不需要多態分派,注入的函數也不一定需要參數(協議需要至少一個參數來調度它的類)。我有什麼選擇?

請注意,Foo和Bar記錄是庫域類型,而render-response方法也是庫域。我不一定在意如何定義它們,但它們所代表的抽象是圖書館領域。

+2

而不是注入,使服務器中的所有調用調用協議方法,並讓客戶端提供實現該協議的類型。 – noisesmith 2015-02-11 23:31:25

+0

我不明白這與我有什麼不同,你可以發佈代碼嗎? – 2015-02-12 03:33:23

回答

1

這是一個有點接近,你會怎麼通常看到用於向圖書館提供了從客戶端代碼的功能協議:

;; lib.clj 
(defprotocol MyLibDependencies 
    (provide-status [this x]) 
    (provide-response [this x])) 

(defn render-response 
    [responder val] 
    {:status (provide-status responder val) 
    :code (provide-response responder val)}) 

;; client.clj 
(defrecord Foo [y] 
    MyLibDependencies 
    (provide-status [this val] 
    (if (even? val) 
     :ok 
     :err)) 
    (provide-response [this val] 
    (+ y val))) 

(defrecord Bar [y] 
    MyLibDependencies 
    (provide-status [this val] 
    (if (odd? val) 
     :ok 
     :err)) 
    (provide-response [this val] 
    (+ y val))) 


(comment 
    (render-response (Bar. 10) 1) ;; => {:status :ok :code 11} 
    (render-response (Foo. 10) 1) ;; => {:status :err :code 11} 
) 

有這種風格在野外的Clojure代碼的例子不勝枚舉 - 事實上構成Clojure本身的大多數核心功能最終都會解析爲調用由正在使用的特定數據結構提供的協議方法,或者針對單個數據類型擴展多方法調用。

+0

可以在保留庫中定義的記錄和方法的情況下完成嗎? – 2015-02-12 17:05:04

+0

您可以使用extend-type將協議實現添加到來自客戶端的記錄中,但我沒有真正看到在lib中定義記錄的好處。適應使用從客戶端傳入的類型的模式與爲了使用顯式傳遞的參數而不是全局狀態所做的設計類型相同。請記住,無論類型如何,您都可以將任何您喜歡的關鍵字關聯到任何記錄上,包括特定於您的庫的名稱空間鍵。 – noisesmith 2015-02-12 22:05:23

相關問題