Абстрактные функции или функциональные интерфейсы в Clojure? - PullRequest
9 голосов
/ 06 января 2010

В ряде случаев у меня есть набор функций, которые я хотел бы реализовать различными способами. Самый очевидный пример этого - абстрагироваться от конкретных баз данных. В объектно-ориентированном языке вы бы использовали интерфейс для этого:

interface DB {
  ResultSet query(String query);
  void persist(Object o);
  ...
}

В коде speudo я хотел бы сделать что-то вроде этого:

(ns dbbackend)

(abstractfn query [q])
(abstractfn persist! [o])

А затем реализации для каждой базы данных:

(ns dbbackend.mysql :implements dbbackend)
(defn query [q] ...)
(defn persist! [o] ...)

Мне не совсем понятно, что лучше всего делать что-то похожее на функциональном языке, особенно на Clojure. Должен ли я использовать несколько методов для этого?

Ответы [ 2 ]

11 голосов
/ 06 января 2010

Теперь, когда версия 1.1 Clojure была выпущена, возможно, пришло время взглянуть в будущее.

Типы данных и протоколы , которые в настоящее время доступны только в новой главной ветви на github , могут быть именно тем, что вы есть ищу.

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

(deftype MySQLBackend []
  DB
  (query   [query] ...)
  (persist [object] ...))
6 голосов
/ 06 января 2010

Для версий протокола Clojure без протокола:

Интерфейс:

(ns dbbackend)

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

(defmulti persist!
  {:arglists '([c o])}
  suitable-dispatch-fn)

Реализация:

(ns dbbackend.mysql
  (:requires dbbackend))

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

(defmethod persist! com.mysql.jdbc.Connection
  [c o]
  ...)

Использование:

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

(def mysql-connection (connect-to-mysql))
(query mysql-connection some-query)

Вы можете найти реальный пример такого подхода под капотом ClojureQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...