2010-01-06 12 views
9

En varias ocasiones tengo una colección de funciones que me gustaría implementar de diferentes maneras. El ejemplo más obvio de esto sería abstraer de bases de datos específicas. En un lenguaje orientado a objetos que utilizaría una interfaz para esto:¿Funciones abstractas o interfaces de funciones en Clojure?

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

en speudo código que me gustaría hacer algo como esto:

(ns dbbackend) 

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

Y luego implementaciones para cada base de datos:

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

No tengo muy claro cuál es la mejor práctica para hacer algo similar en un lenguaje funcional, específicamente Clojure. ¿Debería usar métodos múltiples para esto?

+0

multimétodos parece una combinación razonablemente buena para mí, quizás la única. Pero no soy un experto en Clojure, así que no ofreceré una respuesta "real". +1 para la buena pregunta, sin embargo! –

Respuesta

11

Ahora que se ha lanzado version 1.1 of Clojure tal vez es hora de echar un vistazo al futuro.

Datatypes y protocols, que actualmente solo están disponibles en the new master branch on github, pueden ser exactamente lo que está buscando.

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

(deftype MySQLBackend [] 
    DB 
    (query [query] ...) 
    (persist [object] ...)) 
+1

+1 por la información interesante, pero ay, ¡me duele el cerebro! Clojure parece estar creciendo más rápido de lo que puedo aprender :( –

+0

Leí sobre eso, pero supuse que en su mayoría eran de optimización (Clojure en Clojure, etc.). Sin embargo, parecen encajar aquí también. Gracias. –

6

Para pre-protocolo versiones Clojure:

La interfaz:

(ns dbbackend) 

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

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

La implementación:

(ns dbbackend.mysql 
    (:requires dbbackend)) 

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

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

El uso:

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

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

Puede encontrar un ejemplo real de este enfoque bajo el capó de ClojureQL.

Cuestiones relacionadas