对clojure不熟悉,我想提供一些关于实现存储库模式*的建议。
在OO语言中,我将创建一个存储库接口,一个测试和至少一个db impl。我会在bootstrap中实例化它们,使用DI传递对象或通过服务定位器获取它们。我猜它在clojure中完全不同了吗?
1)在回购中对函数进行分组的好方法是什么?协议,命名空间中的“免费”功能?
2)我在哪里实例化存储库后端,即分配像db-connections等资源?我是否实例化了存储库协议的实现并将其分配给一个原子,或者在自由函数的情况下,重新定义它们?
*)存储库是持久性的后端抽象,通常支持CRUD样式的操作范围。
编辑:这是我目前正在使用的方法。用于分组功能的协议。测试和实现它的“真实”记录。然后用一个原子来注册回购。
(defprotocol GardenRepo
"Repository of Gardens. Supports CRUD style operations."
(list-gardens [repo] "Get a seq of all gardens in the repo.")
(get-garden [repo id] "Get a specific garden by it's id.")
...)
(let [repo (atom nil)]
(defn get-garden-repo [] @locator)
(defn set-garden-repo [new-repo] (reset! repo new-repo)))
答案 0 :(得分:3)
1)按共享子问题分组功能。在我们的ORM中,我们有一个用于db交互的命名空间,一个用于每个目标db的独立命名空间,一个用于模型构造和查询操作的命名空间,一个用于字段定义的命名空间,一个描述字段协议的每个实现的单独命名空间(即int,string ,文本,slug,集合)。
2)使用一个函数返回所有使用的函数,每个函数隐式使用传入的配置定义的资源,即:
(defn make-repository
[config]
(let [db (initialize-db config)
cleanup #(do-cleanup db)
store (fn [key val] (store-data key val db))
retrieve (fn [key] (retrieve-data key db))]
{:db db ;; this is optional, can be very useful during initial development
:cleanup cleanup
:store store
:retrieve retrieve}))
如果函数的访问是性能瓶颈,这当然可以创建记录的实例,如果要定义相同功能的多个实现,则记录可以实现协议(可能需要不同设置的不同db驱动程序)等等。)。库的用户决定如何以及在何处绑定您返回的这些函数,以适合他们自己的设计。
客户端如何使用此存储库的示例:
(def repo (make-repository config))
(def cleanup-repo (:cleanup repo))
(def store-to-repo (:store repo))
(def retrieve-from-repo (:retrieve repo))
(defn store-item
[data]
(let [processed (process data)
key (generate-key data)]
(try (store-to-repo key data)
(catch Exception e
(cleanup-repo)))))