eba*_*axt 7 dao clojure mongodb
我正在尝试将http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded中的想法实现到我的代码库中.
我有一个dao层,我现在需要传入一个数据库以避免全局状态.让我失望的一件事就是:
任何需要其中一个组件的函数都必须将其作为参数.这并不像看起来那么繁琐:每个函数最多只能获得一个额外的参数,提供它运行的"上下文".该上下文可以是整个系统对象,但更常见的是一些子集.通过明智地使用词法闭包,额外的参数从大多数代码中消失.
我应该在哪里使用闭包以避免每次调用都通过全局状态?一个例子是在dao层中创建一个init函数,如下所示:
(defprotocol Persistable
(collection-name [this]))
(def save nil)
(defn init [{:keys [db]}]
(alter-var-root #'save (fn [_] (fn [obj] (mc/insert-and-return db (collection-name obj) obj WriteConcern/SAFE)))))
Run Code Online (Sandbox Code Playgroud)
这样我可以从system/start函数启动我的dao层,如下所示:
(defn start
[{:keys [db] :as system}]
(let [d (-> db
(mc/connect)
(mc/get-db "my-test"))]
(dao/init d)
(assoc system :db d)))
Run Code Online (Sandbox Code Playgroud)
这有效,但感觉有点icky.有没有更好的办法?如果可能的话,我想避免强迫我的dao层的客户端每次使用函数时都必须传递数据库.
您可以使用更高阶函数来表示您的DAO层 - 这是函数式编程的关键,使用函数来表示系统的小到大部分.因此,您有一个更高阶的函数,它将数据库连接作为参数接收,并返回另一个函数,您可以使用该函数调用数据库上的保存,删除等各种操作.以下是一个这样的例子:
(defn db-layer [db-connection]
(let [db-operations {:save (fn [obj] (save db-connection obj))
:delete (fn [obj] (delete db-connection obj))
:query (fn [query] (query db-connection query))}]
(fn [operation & params]
(-> (db-operations operation) (apply params)))))
Run Code Online (Sandbox Code Playgroud)
DB层的用法:
(let [my-db (create-database)
db-layer-fn (db-layer my-db)]
(db-layer-fn :save "abc")
(db-layer-fn :delete "abc"))
Run Code Online (Sandbox Code Playgroud)
这只是高阶函数如何允许您为另一组函数创建上下文的一个示例.通过将其与协议等其他Clojure功能相结合,您可以进一步理解这一概念.
| 归档时间: |
|
| 查看次数: |
764 次 |
| 最近记录: |