python - 如何在运行时配置 Clojure 库?

标签 python dependency-injection clojure

作为 Clojure 学习练习,我正在将 Bulbs ( http://bulbflow.com ),这是我编写的图形数据库库,从 Python 移植到 Clojure。

我仍然有些模糊的事情之一是如何以 Clojure 惯用的方式构建库。

为了支持多个数据库,Bulbs 使用依赖注入(inject)。不同的数据库后端在实现接口(interface)的自定义客户端类中被抽象出来,客户端在运行时配置。

Graph 对象及其各种代理对象包含低级 Client 对象的实例:

# bulbs/neo4jserver/graph.py

class Graph(object):

    default_uri = NEO4J_URI

    def __init__(self, config=None):
        self.config = config or Config(self.default_uri)
        self.client = Neo4jClient(self.config)

        self.vertices = VertexProxy(Vertex, self.client)
        self.edges = EdgeProxy(Edge, self.client)

您可以通过为相应的图形数据库服务器创建图形对象来使用 Bulbs:

>>> from bulbs.neo4jserver import Graph
>>> g = Graph()

然后您可以通过代理对象在数据库中创建顶点和边:

>>> james = g.vertices.create(name="James")
>>> julie = g.vertices.create(name="Julie")
>>> g.edges.create(james, "knows", julie)

这种设计使得从 REPL 中使用 Bulbs 变得很容易,因为您所要做的就是导入和实例化 Graph 对象(或者如果需要,可能传入自定义 Config 对象)。

但我不确定如何在 Clojure 中处理此设计,因为 Graph 对象及其代理需要保存在运行时配置的 Client 对象。

这样做的 Clojure 方式是什么?

更新:这就是我最终做的...

;; bulbs/neo4jserver/client.clj

(def ^:dynamic *config* default-config)

(defn set-config!
  [config]
  (alter-var-root #'*config* (fn [_] (merge default-config config))))

(defn neo4j-client
  [& [config]]
  (set-config! config))

(neo4j-client {:root_uri "http://localhost:7474/data/db/"})

(println *config*)

更新 2:

Andrew Cooke 指出,使用全局变量会使您无法在程序中使用多个独立的图形“实例”,而在 Python 版本中则可以。

所以我想到了这个:

(defn graph
  [& [config]]
  (let [config (get-config config)]
    (fn [func & args]
      (apply func config args))))

(defn create-vertex
  [config data]
  (let [path (build-path vertex-path)
        params (remove-null-values data)]
    (rest/post config path params)))

(defn gremlin
  [config script & [params]]
  (rest/post config gremlin-path {:script script :params params}))

然后你可以像这样调用不同的函数:

(def g (graph {:root_uri "http://localhost:7474/data/db/"}))

(g create-vertex {:name "James"})

(g gremlin "g.v(id)" {:id 178})

现在我还没有深入研究宏,与其他方法相比,我不太确定这种方法的优点,因此欢迎提供反馈。

最佳答案

Protocols在 Clojure 中非常适合这个,你定义一个协议(protocol)(很像一个接口(interface))来定义与数据库接口(interface)所需的所有函数,然后在运行时你调用在协议(protocol)实例中构建的图形协议(protocol)的构造函数连接到您选择的数据库。

除了使用 Clojure 协议(protocol)外,基本流程非常相似。

关于python - 如何在运行时配置 Clojure 库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10540999/

相关文章:

variables - 返回变量作为 map 的 Clojure 惯用解决方案

clojure - 如何映射要执行的 Java 方法的顺序

python - 如何从存储库中删除带有 Django 项目的 virtualenv 并添加 requirements.txt 文件?

php - symfony monolog 中的 channel 是如何定义的?

asp.net-mvc - 用于依赖注入(inject)的 MVC Web API 和 Unity

c# - 如果服务未注册,请勿调用该方法

clojure - 使用 clojure 将 EDN 文件读入 java 对象时如何避免打印对象哈希码

python - 当我尝试安装 virtualenv 时,是什么导致了这个错误? IO错误 : [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/virtualenv.py'

python - Django Rest Framework 全局分页和 pagination_class 不起作用

python - 两个大型数据集的最快迭代合并