2013-07-18 22 views
5

ho qualche codice clojure che assomiglia a questo:Come incapsulare in 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))) 

Ora il seguente codice sembra un po 'poco comune:

(def left :x) 

Tuttavia non so altro modo per ottenere l'incapsulamento.

Supponiamo, in seguito, voglio rappresentare il mio retto in un modo diverso. Quindi fare affidamento su (: x rect) non è una buona idea, perché: x funziona solo su hashmap e record, quindi dovrei rilasciare i dettagli di implementazione nell'api, che almeno nelle lingue OO è considerato una cattiva pratica.

Ora, se decido di realizzare il mio rect in Java, invece, diventa ancora peggio, perché allora avrei dovuto scrivere wrapper come:

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

per assicurarsi che l'interfaccia non cambia.

Come fa Clojure a risolvere questo problema?

risposta

4

È possibile utilizzare i protocolli.

primo un record 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 

Ora un oggetto 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 ha protocols and types. Identifica un'astrazione con un protocollo (come le interfacce Java) e crei implementazioni per tali astrazioni. Ci sono anche multimethods che ti danno più libertà su come avviene la spedizione del metodo.

Tuttavia, strutturare i dati come nel tuo esempio è molto comune. Dai uno sguardo allo Leiningen project file e al contenuto di Ring requests and responses. Anche se hai deciso di cambiare completamente il modo in cui cerchi i valori di xey, puoi semplicemente creare un tipo che operi sulla stessa astrazione di una mappa. In questo caso, questo è il ILookup protocol.