代码之家  ›  专栏  ›  技术社区  ›  Joe Holloway

在Clojure中定义SPI

  •  3
  • Joe Holloway  · 技术社区  · 16 年前

    如果我回到Java反射,我知道有几种方法可以做到这一点,但我觉得在Clojure中实现它将有助于我的理解。

    (注意,我在这里使用的是一般意义上的SPI,而不是专门指在 JAR file specification )

    2 回复  |  直到 16 年前
        1
  •  6
  •   Legends    16 年前

    Clojure是一种非常动态的语言:几乎任何可以在编译时完成的事情都可以在运行时完成。您的“部署配置”可以是一个clojure源文件,在运行时加载到应用程序中。只需调用(加载“my config.clj”)。请注意,如果确实需要,您甚至可以重写特定动态范围中的函数,这样您就可以进行包装 函数(包括核心函数)和另一个函数,该函数表示记录它们的参数、返回值以及运行所用的时间。请查看clojure.contrib.trace以了解如何执行此操作的示例。

        2
  •  7
  •   Brian Carper    16 年前

    Compojure 使用 "middleware" 要处理HTTP请求,您可以查看它的实现。Compojure中的“处理程序”是接受请求并返回响应的函数(请求和响应都是Clojure哈希映射。)“中间件”是一个接受处理程序函数并返回不同处理程序函数的函数。中间件可以改变请求和/或响应;它可以调用它所传递的处理程序(如果愿意,可以重复调用)或短路并忽略处理程序,等等。您可以以任何组合的方式在其他处理程序中包装处理程序。

    由于函数是一流的对象,因此它非常轻量级,易于实现和使用。然而,它不会像您从Java接口获得的那样在编译时强制执行任何内容;这完全是一个遵循惯例和鸭子打字的问题。 Protocols 最终可能对这项任务有好处,但它们暂时不可用(可能在Clojure 2.0中?)

    不确定这是否是您想要的,但这里有一个非常基本的版本:

    ;; 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))))
    

    然后:

    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
    
    推荐文章