2013-07-18 8 views
5

Ich habe einige clojure Code, der wie folgt aussieht:Wie in clojure einzukapseln?

(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))) 

nun der folgende Code scheint ein wenig ungewöhnlich:

(def left :x) 

jedoch weiß, dass ich keine andere Art und Weise Verkapselung zu erhalten.

Angenommen, ich möchte später meinen rect einen anderen Weg darstellen. Dann auf (: x rect) angewiesen ist keine gute Idee, denn: x funktioniert nur auf Hashmaps und Datensätze, so würde ich dann Implementierungsdetails in der API, was zumindest in OO-Sprachen als schlechte Praxis ist leckt.

Nun, wenn ich stattdessen meine rect in Java zu implementieren entscheiden, es wird noch schlimmer, denn dann würde ich Wrapper schreiben müssen wie:

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

um sicherzustellen, dass die Schnittstelle nicht ändert.

Wie löst clojure dieses Problem?

Antwort

4

Sie können Protokolle verwenden.

Zuerst ein Clojure Rekord:

(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 

Jetzt ein Java-Objekt:

(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 hat protocols and types. Sie identifizieren eine Abstraktion mit einem Protokoll (wie Java-Schnittstellen) und Sie erstellen Implementierungen für diese Abstraktionen. Es gibt auch multimethods, die Ihnen mehr Freiheit geben, wie der Methodenversand erfolgt.

Es ist jedoch sehr üblich, Ihre Daten so zu strukturieren, wie Sie es in Ihrem Beispiel getan haben. Werfen Sie einen Blick auf die Leiningen project file und den Inhalt von Ring requests and responses. Selbst wenn Sie sich entschieden haben, die Suche nach den Werten von x und y vollständig zu ändern, können Sie einfach einen Typ erstellen, der auf der gleichen Abstraktion wie eine Karte arbeitet. In diesem Fall ist das die ILookup protocol.