我想将持久层的细节隐藏在某种界面后面。在Java中,我只需要创建一个接口并在某种启动功能中选择正确的实现即可。我仍在努力在Clojure中做到这一点。我在这里不一定需要任何类型安全性,我相信我的单元测试可以在那里找到任何问题。我能想到的最好的办法是创建一个包含带有特定键的匿名函数的映射,如下所示:
(def crux-db {
:get-by-id (fn [id] (get-obj...))
:save (fn [id obj] (store-obj...))
})
(def fs-db {
:get-by-id (fn [id] (get-obj...))
:save (fn [id obj] (store-obj...))
})
如果我没有丢失任何东西,只要所有功能都存在于所有实现映射中,这将使我可以通过定义(def db crux-db)
或(def db fs-db)
来替换数据库实现。不知何故,我觉得这不是clojure的方法,但是我无法将手指放在上面。还有另一种方法吗?
答案 0 :(得分:2)
Protocols是实现此目的的一种方法。它们使您可以定义应该包含哪些功能。和
您可以稍后通过例如
defrecord
。
协议是使用defprotocol定义的一组命名方法及其签名:
(defprotocol AProtocol "A doc string for AProtocol abstraction" (bar [a b] "bar docs") (baz [a] [a b] [a b c] "baz docs"))
- 未提供任何实现方式
- 可以为协议和功能指定文档
- 以上内容产生了一组多态函数和一个协议对象
- 所有名称都由包含定义的名称空间限定
- 结果函数根据其第一个参数的类型进行调度,因此必须至少具有一个参数
- defprotocol是动态的,不需要AOT编译
- defprotocol将自动生成一个与协议同名的相应接口,例如给定一个协议my.ns / Protocol,一个接口my.ns.Protocol。该接口将具有与协议功能相对应的方法,并且该协议将自动与该接口的实例一起使用。
由于您在代码中提到了症结所在,因此可以一窥它们的重要性
用它
here
然后使用defrecord
s实现some of
them
答案 1 :(得分:2)
有几种方法可以实现此目的。一种方法是使用protocols。另一种方法是只使用higher-order functions,在这里您可以“注入”特定的函数并将其公开,如下所示:
(defn get-by-id-wrapper [implementation]
(fn [id]
(implementation id)
...))
(defn cruxdb-get-by-id [id]
...)
(def get-by-id (get-by-id-wrapper cruxdb-get-by-id))