मैं अधिक संक्षिप्त और बेवकूफ इंटरफेस प्रदान करने के लिए ब्रेनट्री जावा लाइब्रेरी के लिए क्लोजर रैपर लिख रहा हूं।क्लोजर मैक्रो?
(transaction-request :amount 10.00 :order-id "user42")
मुझे पता है this question में दिखाया गया है मैं स्पष्ट रूप से यह कर सकते हैं,:: मैं जावा जल्दी से और संक्षेप में वस्तुओं, जैसे दृष्टांत के लिए कार्य करता है प्रदान करना चाहते हैं
(defn transaction-request [& {:keys [amount order-id]}]
(doto (TransactionRequest.)
(.amount amount)
(.orderId order-id)))
लेकिन इसके लिए दोहराव है पैरामीटर वैकल्पिक होने पर कई वर्ग और अधिक जटिल हो जाते हैं। जाहिर है
(defn set-obj-from-map [obj m]
(doseq [[k v] m]
(clojure.lang.Reflector/invokeInstanceMethod
obj (name k) (into-array Object [v])))
obj)
(defn transaction-request [& {:as m}]
(set-obj-from-map (TransactionRequest.) m))
(defn transaction-options-request [tr & {:as m}]
(set-obj-from-map (TransactionOptionsRequest. tr) m))
, मैं अगर संभव हो प्रतिबिंब से बचने के लिए करना चाहते हैं: प्रतिबिंब का उपयोग करना, यह बहुत अधिक संक्षेप में इन कार्यों को परिभाषित करना संभव है। मैंने set-obj-from-map
के मैक्रो संस्करण को परिभाषित करने का प्रयास किया लेकिन मेरा मैक्रो-फू पर्याप्त मजबूत नहीं है। here समझाया गया है कि इसे शायद eval
की आवश्यकता है।
क्या प्रतिबिंब का उपयोग किए बिना रनटाइम पर निर्दिष्ट जावा विधि को कॉल करने का कोई तरीका है?
अग्रिम धन्यवाद!
अपडेट किए गए समाधान:
जूस्ट से सलाह के बाद, मैं एक ऐसी ही तकनीक का उपयोग कर समस्या को हल करने में सक्षम था। एक मैक्रो संकलन-समय पर प्रतिबिंब का उपयोग करता है यह पहचानने के लिए कि कक्षा में कौन से सेटर तरीके हैं और फिर मानचित्र में परम की जांच करने के लिए फॉर्म को थूकते हैं और विधि को इसके मूल्य के साथ कॉल करते हैं।
; Find only setter methods that we care about
(defn find-methods [class-sym]
(let [cls (eval class-sym)
methods (.getMethods cls)
to-sym #(symbol (.getName %))
setter? #(and (= cls (.getReturnType %))
(= 1 (count (.getParameterTypes %))))]
(map to-sym (filter setter? methods))))
; Convert a Java camelCase method name into a Clojure :key-word
(defn meth-to-kw [method-sym]
(-> (str method-sym)
(str/replace #"([A-Z])"
#(str "-" (.toLowerCase (second %))))
(keyword)))
; Returns a function taking an instance of klass and a map of params
(defmacro builder [klass]
(let [obj (gensym "obj-")
m (gensym "map-")
methods (find-methods klass)]
`(fn [~obj ~m]
[email protected](map (fn [meth]
`(if-let [v# (get ~m ~(meth-to-kw meth))] (. ~obj ~meth v#)))
methods)
~obj)))
; Example usage
(defn transaction-request [& {:as params}]
(-> (TransactionRequest.)
((builder TransactionRequest) params)
; some further use of the object
))
पसंद करेंगे क्या बिना प्रतिबिंब? लगभग निश्चित रूप से नहीं। –
ठीक है, किसी मैक्रो का उपयोग करके प्रतिबिंब_ के बिना विधि कॉल में मानचित्र का अनुवाद करना संभव है। मैंने केवल यह महसूस करने पर प्रतिबिंब का उपयोग किया कि मैक्रो नक्शा धारण करने वाला प्रतीक नहीं ले सकता है, बल्कि केवल कच्चा नक्शा ही है। मुझे यह कहने में शायद अधिक स्पष्ट होना चाहिए कि मैं _runtime_ पर प्रतिबिंब से बचना चाहता हूं, जैसे @ joost-diepenmaat नीचे वर्णित है। – bkirkbri