Clojure中的抽象函数或函数接口?

Zef*_*mel 9 clojure

在很多场合,我有一系列功能,我想以不同的方式实现.最明显的例子是从特定数据库中抽象出来.在面向对象的语言中,您将使用一个接口:

interface DB {
  ResultSet query(String query);
  void persist(Object o);
  ...
}
Run Code Online (Sandbox Code Playgroud)

在speudo代码中,我想做这样的事情:

(ns dbbackend)

(abstractfn query [q])
(abstractfn persist! [o])
Run Code Online (Sandbox Code Playgroud)

然后是每个数据库的实现:

(ns dbbackend.mysql :implements dbbackend)
(defn query [q] ...)
(defn persist! [o] ...)
Run Code Online (Sandbox Code Playgroud)

对我来说,最好的做法是用功能语言,特别是Clojure做类似的事情,这一点并不完全清楚.我应该使用多种方法吗?

Jon*_*nas 11

现在已经发布了Clojure的1.1版,也许是时候看看未来了.

数据类型协议目前仅在github上新主分支中可用,可能正是您正在寻找的.

(defprotocol DB
  (query   [backend query])
  (persist [backend object]))

(deftype MySQLBackend []
  DB
  (query   [query] ...)
  (persist [object] ...))
Run Code Online (Sandbox Code Playgroud)


kot*_*rak 6

对于预协议Clojure版本:

界面:

(ns dbbackend)

(defmulti query
  {:arglists '([c q])}
  suitable-dispatch-fn)

(defmulti persist!
  {:arglists '([c o])}
  suitable-dispatch-fn)
Run Code Online (Sandbox Code Playgroud)

实施:

(ns dbbackend.mysql
  (:requires dbbackend))

(defmethod query com.mysql.jdbc.Connection
  [c q]
  ...)

(defmethod persist! com.mysql.jdbc.Connection
  [c o]
  ...)
Run Code Online (Sandbox Code Playgroud)

用法:

(ns user
  (:require dbbackend dbbackend.mysql))

(def mysql-connection (connect-to-mysql))
(query mysql-connection some-query)
Run Code Online (Sandbox Code Playgroud)

您可以在ClojureQL的引擎下找到这种方法的真实示例.