2013-07-18 23 views
5

Mam niektóre kodu Clojure, który wygląda tak:Jak hermetyzować w 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))) 

Teraz następujący kod wydaje się nieco Niezbyt często:

(def left :x) 

Jednak nie znam żadnego innego sposobu na zdobycie enkapsulacji.

Załóżmy, że później chcę reprezentować mój rect w inny sposób. Wówczas poleganie na (: x rect) nie jest dobrym pomysłem, ponieważ: x działa tylko na hashmapach i zapisach, więc wtedy byłyby nieszczelne szczegóły implementacji w api, co przynajmniej w językach OO jest uważane za złą praktykę.

Teraz, jeśli zdecyduję się realizować moje rect w java zamiast, to jeszcze gorzej, bo wtedy musiałbym napisać obwolut jak:

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

aby upewnić się, że interfejs nie zmienia.

W jaki sposób clojure rozwiązuje ten problem?

Odpowiedz

4

Możesz używać protokołów.

Pierwszy rekord 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 

Teraz obiekt 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 ma protocols and types. Identyfikujesz abstrakcję za pomocą protokołu (np. Interfejsów Java) i tworzysz implementacje dla tych abstrakcji. Istnieją również multimethods, które dają większą swobodę w zakresie sposobu wysyłania metody.

Jednak porządkowanie danych w sposób opisany w przykładzie jest bardzo częste. Spójrz na Leiningen project file i zawartość Ring requests and responses. Nawet jeśli zdecydujesz się całkowicie zmienić sposób wyszukiwania wartości x i y, możesz po prostu utworzyć typ, który działa na tej samej abstrakcji co mapa. W tym przypadku jest to ILookup protocol.