如何封装在clojure中?

Mos*_*erd 5 encapsulation clojure wrapper

我有一些看起来像这样的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)))
Run Code Online (Sandbox Code Playgroud)

现在,以下代码似乎有点不常见:

(def left :x)
Run Code Online (Sandbox Code Playgroud)

但是,我不知道任何其他方式来获得封装.

假设,我后来想以不同的方式表示我的矩形.然后依赖(:x rect)不是一个好主意,因为:x只适用于hashmap和记录,因此我会在api中泄漏实现细节,至少在OO语言中被认为是不好的做法.

现在,如果我决定在java中实现我的rect,它会变得更糟,因为那时我必须编写包装器,如:

(defn left [rect] (.getLeft rect))
Run Code Online (Sandbox Code Playgroud)

确保界面不会改变.

clojure如何解决这个问题?

A. *_*ebb 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
Run Code Online (Sandbox Code Playgroud)

现在是一个 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
Run Code Online (Sandbox Code Playgroud)