我有一些看起来像这样的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中实现我的rect,它会变得更糟,因为那时我必须编写包装器,如:
(defn left [rect] (.getLeft rect))
确保界面不会改变。
clojure如何解决这个问题?
答案 0 :(得分: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
答案 1 :(得分:2)
Clojure有protocols and types。您使用协议(如Java接口)识别抽象,并为这些抽象创建实现。还有multimethods使您可以更自由地调度方法。
但是,以您在示例中的方式构建数据非常常见。请查看Leiningen project file和Ring requests and responses的内容。即使您决定完全更改查找x和y值的方式,也可以创建一个与地图相同的抽象操作类型。在这种情况下,那是ILookup protocol。