gpt4 book ai didi

clojure - 在 Clojure 中定义 SPI

转载 作者:行者123 更新时间:2023-12-02 18:41:09 25 4
gpt4 key购买 nike

我正在寻找一种惯用的方法来定义 Clojure 中的接口(interface),该接口(interface)可以由外部“服务提供者”实现。我的应用程序将在运行时定位并实例化服务提供者模块,并将某些职责委托(delegate)给它。

例如,假设我正在实现 RPC 机制,并且希望允许在配置时注入(inject)自定义中间件。该中间件可以预处理消息、丢弃消息、使用日志记录包装消息处理程序等。

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

(注意,我在这里使用一般意义上的 SPI,而不是具体指 JAR file specification 中定义它的方式)

谢谢

最佳答案

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

由于函数是一流对象,因此它非常轻量级且易于实现和使用。然而,它不会像从 Java 接口(interface)中得到的那样在编译时强制执行任何操作;这都是遵循惯例和鸭子类型的问题。 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

关于clojure - 在 Clojure 中定义 SPI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1810231/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com