문제

외부 "서비스 제공 업체"가 구현할 수있는 Clojure의 인터페이스를 정의하는 관용적 인 방법을 찾고 있습니다. 내 응용 프로그램은 런타임에 서비스 제공 업체 모듈을 찾고 인스턴스화하고 특정 책임을 위임합니다.

예를 들어, RPC 메커니즘을 구현하고 구성 시간에 사용자 정의 미들웨어를 주입 할 수 있도록하고 싶습니다. 이 미들웨어는 메시지를 사전 처리하고 메시지를 버리고 로깅 등으로 메시지 핸들러를 포장 할 수 있습니다.

나는 Java Reflection으로 돌아 가면 이것을하는 몇 가지 방법을 알고 있지만 Clojure에서 그것을 구현하면 내 이해에 도움이 될 것이라고 생각합니다.

(참고, 나는 여기에서 일반적인 의미에서 SPI를 사용하고 있으며, 그것이 정의 된 방식을 구체적으로 언급하지 않습니다. JAR 파일 사양)

감사

도움이 되었습니까?

해결책

Clojure는 매우 역동적 인 언어입니다. 컴파일 타임에 수행 할 수있는 거의 모든 것은 런타임에 수행 할 수 있습니다. "배포 구성"은 단순히 런타임에 응용 프로그램에로드되는 Clojure 소스 파일 일 수 있습니다. 그냥 전화 ( "my-config.clj"로드). 실제로 원하는 경우 특정 동적 범위에서 기능을 재정의 할 수도 있으므로 포장 할 수 있습니다. 어느 기능 (핵심 함수 포함)은 인수, 반환 가치 및 실행 시간이 얼마나 걸렸다 고 말하는 또 다른 기능과 함께. clojure.contrib.trace를 살펴보면이 작업을 수행하는 방법의 예를 들어보십시오.

다른 팁

작곡 용도 "미들웨어" HTTP 요청을 처리하려면 구현을 볼 수 있습니다. Compojure의 "핸들러"는 요청을 받고 응답을 반환하는 함수입니다. (요청 및 응답은 모두 Clojure 해시 맵입니다.) "미들웨어"는 핸들러 기능을 취하고 다른 핸들러 기능을 반환하는 함수입니다. 미들웨어는 요청, 응답 또는 둘 다를 변경할 수 있습니다. 전달 된 핸들러를 호출하거나 (원하는 경우 반복적으로) 또는 핸들러를 무시하고 무시할 수 있습니다. 다른 핸들러의 핸들러를 어떤 조합 으로든 핸들러를 랩핑 할 수 있습니다.

기능이 일류 개체 인 기능 덕분에 이것은 매우 가볍고 구현 및 사용하기 쉽습니다. 그러나 Java 인터페이스에서 얻을 때 컴파일 시간에 어떤 것도 시행하지 않습니다. 그것은 모두 컨벤션과 오리 타자를 따르는 문제입니다. 프로토콜 결국이 작업에 좋을 수도 있지만 한동안 사용할 수는 없습니다 (아마도 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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top