2013-08-22 8 views
5

मुझे कक्षाओं का एक सेट मिला जो एक संदेश का प्रतिनिधित्व करता है जिसे संभालना है। लेकिन हैंडलरों के लिए केवल सीमित मात्रा में खुले स्थान हैं। इसलिए किसी संदेश ऑब्जेक्ट को संभालने वाले हैंडलर के किसी भी "प्रेषण" को पहले यह जांचना पड़ता है कि कोई खाली स्थान है या नहीं।विधि संयोजन का उपयोग करके कोड डुप्लिकेशन को कैसे कम करें, लेकिन संभावित प्रारंभिक वापसी

यदि वहां है -> प्रेषण।

अगर वहाँ नहीं है -> प्रेषण और इसी संदेश

कोड के इस भाग के रूप में किसी भी प्रेषण विधि मैं लगा यह लागू करने के लिए है कि विधि संयोजन सुविधा का उपयोग करने के लिए सबसे अच्छा होगा में ही होगा नहीं लौटते , लेकिन मैं यह नहीं समझ सकता कि कैसे।

मेरे वर्तमान कोड बेस में मैं का उपयोग करने की कोशिश की एक: विधि से पहले, लेकिन जाहिरा तौर पर आप इस तरह के संदर्भ में वापसी का उपयोग नहीं कर सकते हैं:

(defclass message() ((msg :initarg :msg :reader msg))) 

(defclass message-ext (message) 
    ((univ-time :initarg :univ-time :reader univ-time))) 

(defparameter *open-handler* nil) 

(defgeneric handle (message) 
    (:documentation "handle the given message appropriately")) 

(defmethod handle :before ((message message)) 
    (when (> (length *open-handler*) 1) 
    (return :full))) 

(defmethod handle ((message message)) 
    (push (FORMAT nil "dispatched handler") *open-handler*)) 

(defmethod handle ((message-ext message-ext)) 
    (push (FORMAT nil "dispatched ext handler") *open-handler*)) 

(handle (make-instance 'message :msg "allemeineentchen")) 

(handle (make-instance 'message-ext 
         :msg "rowrowrowyourboat" 
         :univ-time (get-universal-time))) 

(handle (make-instance 'message-ext 
         :msg "gentlydownthestreet" 
         :univ-time (get-universal-time))) 

Execution of a form compiled with errors. 
Form: 
    (RETURN-FROM NIL FULL) 
Compile-time error: 
    return for unknown block: NIL 
    [Condition of type SB-INT:COMPILED-PROGRAM-ERROR] 

Restarts: 
0: [RETRY] Retry SLIME interactive evaluation request. 
1: [*ABORT] Return to SLIME's top level. 
2: [TERMINATE-THREAD] Terminate this thread (#<THREAD "worker" RUNNING {100594F743}>) 

Backtrace: 
    0: ((SB-PCL::FAST-METHOD HANDLE :BEFORE (MESSAGE)) #<unavailable argument> #<unavailable argument> #<unavailable argument>) 
    1: ((SB-PCL::EMF HANDLE) #<unavailable argument> #<unavailable argument> #<MESSAGE-EXT {1005961733}>) 
    2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (HANDLE (MAKE-INSTANCE 'MESSAGE-EXT :MSG "gentlydownthestreet" :UNIV-TIME (GET-UNIVERSAL-TIME))) #<NULL-LEXENV>) 
    3: (EVAL (HANDLE (MAKE-INSTANCE 'MESSAGE-EXT :MSG "gentlydownthestreet" :UNIV-TIME (GET-UNIVERSAL-TIME)))) 
    4: ((LAMBDA() :IN SWANK:INTERACTIVE-EVAL)) 

इस दृष्टिकोण भी समझदार है, और हाँ मैं इसे कैसे में कर सकते हैं, तो एक कामकाजी फैशन? (मैं पहले से ही एक ही परिणाम के साथ return-from का प्रयास किया)

उत्तर

4

मुझे लगता है कि आप :around विधि क्वालीफायर के बजाय का उपयोग करना चाहिए:

(defmethod handle :around ((message message)) 
    (if (cddr *open-handler*) 
     :full 
     (call-next-method))) 

हालांकि, एक अधिक "lispy" दृष्टिकोण का उपयोग करने के लिए है CL Condition System, जैसे, कुछ इस तरह:

(define-condition too-many-messages (...) (...) ...) 
(defun add-message (message) 
    (when (cddr *open-handler*) 
    (signal 'too-many-messages)) 
    (push message *open-handler*)) 
(defmethod handle ((message message)) 
    (add-message (FORMAT nil "dispatched handler"))) 

आप अपने handle समारोह की वापसी मान की जाँच के अलावा हालत (का उपयोग करते हुए, जैसे, handler-bind) को संभालने के लिए होगा।

पीएस। एक सूची में length पर कॉल करना यह जांचने के लिए कि यह काफी लंबा विचार नहीं है - हालांकि आपके मामले में, जब सूची कम होने की गारंटी दी जाती है, तो यह शैली शैली का अधिक हो सकता है।

पीपीएस। handle शब्द को अपने फ़ंक्शन के नाम के रूप में उपयोग करना बहुत अच्छा विचार नहीं है क्योंकि सीएल में ऐसे फ़ंक्शन हैं जिनमें यह शामिल है (उदा।, handler-case)। यह आपके कोड को पढ़ने वाले लोगों को भ्रमित करने के अलावा आपके कोड में खोज को जटिल करेगा।

1

आप इस तरह के फ़ंक्शन से वापस आने के लिए RETURN पर कॉल नहीं कर सकते।

आपको फ़ंक्शन नाम के साथ RETURN-FROM का उपयोग करने की आवश्यकता होगी। लेकिन यहां यह विधि से वापस आ जाएगा - जेनेरिक फ़ंक्शन नहीं।

@sds का उत्तर है। एक और उपयोगकर्ता को परिभाषित स्थिति सिग्नल करना होगा और इसे कहीं और संभालना होगा। पुराना कोड catch और throw का उपयोग किया गया।

एक और जटिल उपक्रम उपयोगकर्ता परिभाषित विधि संयोजन होगा।

संबंधित मुद्दे