Frage

Ich suche nach einem idiomatischen Weg (e) eine Schnittstelle in Clojure zu definieren, die von einem externen „Diensteanbieter“ umgesetzt werden können. Meine Anwendung würde das Service-Provider-Modul zur Laufzeit und delegiert bestimmte Verantwortlichkeit, um es zu finden und instanziiert.

Lassen Sie uns zum Beispiel sagen, dass ich einen RPC-Mechanismus bin Implementierung und ich möchte eine benutzerdefinierte Middleware ermöglichen, bei der Konfiguration injiziert werden. Diese Middleware könnte die Nachricht vorverarbeitet, Nachrichten verwerfen, wickeln Sie die Message-Handler mit Protokollierung, etc.

Ich kenne mehr Möglichkeiten, dies zu tun, wenn ich zurück zu Java Reflexion fallen, aber das Gefühl, dass es in Clojure Umsetzung würde mein Verständnis helfen.

(Beachten Sie, ich bin mit SPI in einem allgemeinen Sinn hier nicht speziell auf die Art und Weise beziehen es in der JAR-Datei-Spezifikation )

Danke

War es hilfreich?

Lösung

Clojure ist eine sehr dynamische Sprache: fast alles, was zum Zeitpunkt der Kompilierung durchgeführt werden kann, kann zur Laufzeit erfolgen. Ihre „Deployment-Konfiguration“ könnte einfach eine clojure Quelldatei sein, die in die Anwendung zur Laufzeit geladen werden. Rufen Sie einfach an (load "my-config.clj"). Beachten Sie, dass Sie auch Funktionen in einem bestimmten Dynamikumfang außer Kraft setzen können, wenn Sie es wirklich wollen, so können Sie wickeln jeder Funktion (einschließlich Kernfunktionen) mit einer anderen, die sagen, dass ihre Argumente anmeldet, Rückgabewert und wie lange sie nahmen laufen. Werfen Sie einen Blick auf clojure.contrib.trace für ein Beispiel dafür, wie dies zu tun.

Andere Tipps

Compojure verwendet „Middleware“ HTTP-Anfragen zu behandeln, können Sie bei deren Umsetzung aussehen. A „handler“ in Compojure ist eine Funktion, die eine Anforderung und gibt eine Antwort erfolgt. (Request und Response sind beiden Clojure Hash-Maps.) „Middleware“ ist eine Funktion, die eine Behandlungsfunktion nimmt, und gibt eine andere Behandlungsfunktion. Middleware kann ändern, um die Anfrage, wobei die Antwort, oder beides; es kann den Handler nennt es übergeben wird (immer wieder, wenn er will) oder Kurzschluss und die Handler ignorieren, etc. Sie können auf diese Weise in anderen Handler wickeln Handler in beliebiger Kombination.

Dank Funktionen erstklassige Objekte zu sein, das ist sehr leicht und einfach zu implementieren und zu verwenden. Allerdings ist es nicht irgendetwas bei der Kompilierung durchzusetzen, wie Sie von einer Java-Schnittstelle erhalten würden; es ist alles eine Frage der folgenden Konventionen und Ente-Typisierung. Protokolle könnte schließlich für diese Aufgabe gut sein, aber sie gehen nicht auf eine Zeit lang zur Verfügung steht (wahrscheinlich in Clojure 2.0?)

Nicht sicher, ob dies ist, was Sie wollen, aber hier ist eine sehr rudimentäre Version:

;; Handler
(defn default [msg]
  {:from "Server"
   :to (:from msg)
   :response "Hi there."})

;; Middleware
(defn logger [handler]
  (fn [msg]
    (println "LOGGING MESSAGE:" (pr-str msg))
    (handler msg)))

(defn datestamper [handler]
  (fn [msg]
    (assoc (handler msg)
      :datestamp (.getTime (java.util.Calendar/getInstance)))))

(defn short-circuit [handler]
  (fn [msg]
    {:from "Ninja"
     :to (:from msg)
     :response "I intercepted your message."}))

;; This would do something with a response (send it to a remote server etc.)
(defn do-something [response]
  (println ">>>> Response:" (pr-str response)))

;; Given a message and maybe a handler, handle the message
(defn process-message
  ([msg] (process-message msg identity))
  ([msg handler]
     (do-something ((-> default handler) msg))))

Dann:

user> (def msg {:from "Chester" :to "Server" :message "Hello?"})
#'user/msg
user> (process-message msg)
>>>> Response: {:from "Server", :to "Chester", :response "Hi there."}
nil
user> (process-message msg logger)
LOGGING MESSAGE: {:from "Chester", :to "Server", :message "Hello?"}
>>>> Response: {:from "Server", :to "Chester", :response "Hi there."}
nil
user> (process-message msg (comp logger datestamper))
LOGGING MESSAGE: {:from "Chester", :to "Server", :message "Hello?"}
>>>> Response: {:datestamp #<Date Fri Nov 27 17:50:29 PST 2009>, :from "Server", :to "Chester", :response "Hi there."}
nil
user> (process-message msg (comp short-circuit logger datestamper))
>>>> Response: {:from "Ninja", :to "Chester", :response "I intercepted your message."}
nil
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top