2013-07-18 100 views
5

我有一些Clojure的代碼看起來像這樣:如何封裝clojure?

(defn rect [x y w h] 
    {:x x, :y y, :w w, :h h}) 

(def left :x) 
(def top :y) 
(def width :w) 
(def height :h) 

(defn right [r] 
    (+ (left r) (width r))) 

(defn bottom [r] 
    (+ (top r) (height r))) 

現在下面的代碼似乎有點少見:

(def left :x) 

但是我不知道任何其他方式獲得的封裝。

假設我後來想用不同的方式來表示我的矩形。 然後依靠(:x rect)並不是一個好主意,因爲:x只對hashmap和記錄起作用,所以我會在api中泄漏實現細節,至少在OO語言中這被認爲是不好的做法。現在

,如果我決定執行我在java中矩形相反,它會變得更糟,因爲那樣我會寫這樣的包裝:

(defn left [rect] (.getLeft rect)) 

,以確保該接口並沒有改變。

clojure如何解決這個問題?

回答

4

您可以使用協議。

首先一個Clojure的記錄:

(defprotocol Rectangular 
    (left [this]) 
    (right [this])) 

(defrecord Rect [x y w h] 
    Rectangular 
    (left [this] x) 
    (right [this] (+ x w))) 

(def my-rect (Rect. 1 2 3 4)) 
(right my-rect) ;=> 4 

現在的Java對象:

(import java.awt.Rectangle) 

(extend-type Rectangle 
    Rectangular 
    (left [this] (int (.getX this))) 
    (right [this] (int (+ (.getX this) (.getWidth this))))) 

(def my-other-rect (Rectangle. 1 2 3 4)) 
(right my-other-rect) ;=> 4 
2

Clojure有protocols and types。您通過協議(如Java接口)識別抽象,併爲這些抽象創建實現。此外還有multimethods,它可以讓您更方便地調度方法調度。

但是,以您在示例中使用的方式構建數據非常普遍。看看Leiningen project fileRing requests and responses的內容。即使你決定完全改變你如何查找x和y的值,你也可以簡單地創建一個類型,它和map一樣運行在同一個抽象上。在這種情況下,這是ILookup protocol