Clojure中协议/多方法的环境依赖调度

6
我遇到了一个问题,即如何构建我软件中的特定部分。假设我有一个名为make-temp-dir(以及许多其他函数)的函数,它会根据当前操作系统执行某些黑魔法。我想能够将每个操作系统的这些方法的实现放在单独的命名空间中。
首先,我认为协议(如果可能的话)或多方法是解决此问题的方案。但是,我从未见过使用跨越多个命名空间的实现示例。我无法想象这该如何解决。
其次,如果我使用协议来实现这一点,我将不得不将方法命名为类似于:
(make-temp-dir current-os arg-1 arg-2)

在我看来,一直将操作系统作为第一个参数传递并不是很好的做法。出于语义上的考虑,我希望make-temp-dir可以根据操作系统自动做出智能决策。当然,我可以使用一些宏并执行类似的操作。

(doto current-os
  (make-temp-dir arg-1 arg2))

但这感觉不对。

应该如何做?还是我走错了方向?任何帮助都将不胜感激。

编辑:好的,非常感谢@kotarak,我设法让它工作了。对于任何遇到此问题的人,可以使用https://gist.github.com/2477120。它运行良好,我想我会选择这个。谢谢大家。

2个回答

7
(ns your.utils)

(def current-os)

(defmulti make-temp-dir
  (fn [& _] current-os))

(ns your.utils.mac)

(defmethod make-temp-dir :mac-os-x
  [a b]
  (...))

(ns your.utils.win)

(defmethod make-temp-dir :windows
  [a b]
  (...))

在您的启动代码中,必须使用alter-var-root初始化current-os,然后才能使用任何实用函数。
(let [os (find-os)]
  (alter-var-root #'current-os (constantly os))
  (require (case os
             :mac-os-x 'your.utils.mac
             :windows  'your.utils.win)))

希望这能帮助你开始。

所以,第二段代码需要在 your.utils 命名空间下,对吧?另外,#' 读取器宏是什么 - 抱歉,我也不知道该如何搜索 ;) - sharat87
#'被称为变量引用。您可以在https://groups.google.com/forum/?fromgroups#!topic/clojure/jDBAJD4nWqs找到有关变量引用的描述。 - user100464
@kotarak,好的,非常棒的解决方案。我花了很长时间来消化它,但我认为我明白了正在发生的事情。不过,我仍然希望对我的第一条评论进行一些输入。 - sharat87
@user100464,感谢提供链接。我正在查看。 - sharat87
@kotarak,这个解决方案需要所有实现命名空间都在同一个文件中吗?这有点违背了将它们放在不同命名空间中的目的,不是吗? - sharat87
显示剩余2条评论

1

我不能确定,但听起来你可能会重复造轮子,而Java已经为你提供了这个功能。尝试使用https://github.com/Raynes/fs,它是一个方便的包装器,可以在clojure.java.io(http://clojuredocs.org/clojure_core/clojure.java.io)基本工具之外提供一些Java提供的功能。

如果你的问题超出了特定于操作系统的分支到环境特定的配置值,你可能也会发现https://github.com/drakerlabs/milieu有用。我编写了这段代码作为我们在Draker的专有项目的一部分,并且我们最近将其作为免费软件发布。我们还没有正式向社区宣布它,但它已经在Clojars中并且可以使用。欢迎反馈!驱动其创建的概念是开发/测试/暂存/生产等意义上的环境,但我认为它也可以用于配置不同操作系统环境的变量。


1
谢谢您提供的链接,rplevy。我认为fs包对我很有用 :) - sharat87

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接