我正在尝试在clojure中创建模块化应用程序。
让我们假设我们有一个博客引擎,它包含两个模块,例如 - 数据库模块和文章模块(存储博客文章的东西),所有模块都有一些配置参数。
所以 - 文章模块依赖于存储,并且有两个文章模块和数据库模块实例(具有不同的参数)允许我们在两个不同的数据库中托管两个不同的博客。
我尝试实现为即时创建每个初始化模块的新命名空间,并使用部分应用的参数定义此命名空间中的函数。但我认为这种做法是某种黑客行为。
这样做的正确方法是什么?
答案 0 :(得分:3)
'模块'是名词,如Steve Yegge的'Kingdom of Nouns'。
尽可能地坚持其参数(动词)的非副作用或纯函数,除非在抽象的最顶层。您可以随意组织这些功能。在最顶层你将有一些应用程序状态,有很多方法来管理它,但我最常用的是在clojure协议下隐藏这些顶级服务,然后在clojure记录中实现它(可能持有引用数据库连接或某些内容。)
这种方法可以最大限度地提高灵活性,并防止您将自己写入角落。它与java的依赖注入类似。 Stuart Sierra最近在Clojure / West 2013上就这些话题进行了很好的讨论,但视频尚未公布。
请注意与您的方法不同。您需要将对象的管理和解决方案与其生命周期分开。将它们绑定到命名空间可以快速访问,但这意味着您编写的任何函数作为使用该代码的客户端现在都在访问全局状态。使用协议,您可以将全局状态的实现细节与访问接口分开。
如果您需要一个激励性的例子说明为什么这有用,请考虑一下,您如何拦截对全球可访问服务的所有访问?好吧,您将推送完整实现并使入口点成为包装函数,而不是将相关详细信息推向客户端代码。如果您想要代码的某些客户端而不是其他客户端的某些行为怎么办?现在你被卡住了。这只是期待以先发制人的方式进行不可避免的权衡,让您的生活更轻松。