我正在编写一个小型的Clojure应用程序,该应用程序与具有2-3个不同集合的MongoDB数据库进行了大量交互。
我来自OOP / Ruby / ActiveRecord背景,其中标准做法是为每个数据模型创建一个类,并为每个数据模型提供访问权限。我在我的clojure项目中开始做同样的事情。每个“数据模型”都有一个命名空间,每个命名空间都有自己的数据库连接和CRUD函数。但是,这感觉不是非常实用或类似于clojure,我想知道是否有一种更惯用的方法,例如拥有data
或database
命名空间,其函数如{{{ 1}},并将对数据库的访问权限仅限于该命名空间。
这似乎有利于将数据库客户端依赖关系仅隔离到一个命名空间,并且还将纯函数与具有副作用的函数分离。
另一方面,我还需要一个名称空间,我需要从我的应用程序的许多不同部分引用它,并且拥有一个名为“data”的名称空间对我来说似乎很奇怪。
在Clojure中是否有传统的惯用方式?
答案 0 :(得分:2)
在Clojure应用程序中管理状态的最常用的(scored 'adopt' on the Clojure radar)方法是由Stuart Sierra的伟大Component库提出的。简而言之,Component的哲学是将所有有状态资源存储在一个system
映射中,该映射明确定义了它们之间的相互关系,然后以这样一种方式构建代码,使得函数只是将状态传递给彼此。
答案 1 :(得分:2)
您系统的一部分将是管理机器'您的应用程序:启动Web服务器,连接数据存储,检索配置等。将此部分放在命名空间中与业务逻辑分开的命名空间(您的业务逻辑命名空间不应该知道此命名空间!)。正如@superkondukr所说,Component是一种经过实战考验且记录良好的方法。
将数据库连接(以及其他环境依赖关系)与业务逻辑通信的推荐方法是 通过函数参数,而不是全局Vars。 这将使一切都更可测试,REPL友好,并明确谁依赖谁。
因此,您的业务逻辑函数将接收连接作为参数并将其传递给其他函数。但是,连接首先来自哪里?我这样做的方法是在进入系统时将它附加到事件/请求。例如,当您启动HTTP服务器时,将连接附加到每个进入的HTTP请求。
在OO语言中,对数据的传统支持是表示数据库实体的类的实例;为了提供惯用的OO接口,业务逻辑然后被定义为这些类的方法。正如埃里克·诺曼德(Eric Normand)在最近的一份时事通讯中所说的那样,你可以定义你的模特的名字'作为班级和动词'作为方法。
因为Clojure强调简单的数据结构来传递信息,所以你真的没有这些激励。您可以仍然按实体组织您的命名空间来模仿它,但我实际上并不认为它是最佳的。您还应该考虑到Clojure命名空间与大多数OO语言中的类不同,不允许循环引用。
我的策略是: 按用例 组织您的命名空间。
例如,假设您的域模型包含用户和帖子。您可能拥有用于用户CRUD和核心业务逻辑的myapp.user
命名空间;同样,您可能拥有myapp.post
命名空间。也许在您的应用中,用户可以喜欢帖子,在这种情况下,您可以在myapp.like
命名空间中对此进行管理,这需要myapp.user
和myapp.posts
。也许您的用户可以成为您应用中的朋友,您可以在myapp.friendship
命名空间中管理这些朋友。也许您有一个小型的后台应用程序,其中包含有关所有这些的数据可视化:例如,您可以将其放在myapp.aggregations
命名空间中。