Repository pattern in clojure



作为 clojure 的新手,我想得到一些关于实现存储库模式的建议*。

在OO语言中,我会创建一个存储库接口,一个测试和至少一个db impl。我会在引导过程中实例化它们,使用 DI 传递对象或通过服务定位器获取它们。我猜它在 clojure 中完全不同?

1) 在存储库中对功能进行分组的好方法是什么?协议,命名空间中的"自由"函数?

2) 我在哪里实例化存储库后端,即分配数据库连接等资源?我是否实例化存储库协议的实现并将其分配给原子,或者在自由函数的情况下,重新定义它们?

*)存储库是持久性的后端抽象,通常支持 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)))

1) 按共享子问题对函数进行分组。在我们的ORM中,我们有一个用于数据库交互的命名空间,每个目标数据库的单独命名空间,一个用于模型构造和查询操作的命名空间,一个用于字段定义的命名空间,一个描述字段协议的每个实现的单独命名空间(即int,string,text,slug,collection)。

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}))

当然,如果函数的访问是性能瓶颈,这可以创建记录的实例,如果要定义同一功能的多个实现(可能需要不同设置的不同数据库驱动程序等),则记录可以实现协议。库的用户根据自己的设计决定如何以及在何处绑定返回的这些函数。

客户端如何使用此存储库的示例:

(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)))))

最新更新