5

我有一组代表必须处理的消息的类。但是对于处理程序来说,只有有限数量的空位。因此,处理消息对象的处理程序的任何“调度”必须首先检查是否有空闲点。

如果有 -> 调度。

如果没有 -> 不发送并返回相应的消息

由于这部分代码在任何调度方法中都是相同的,我认为最好使用方法组合工具来强制执行,但我不知道如何。

在我当前的代码库中,我尝试使用 :before 方法,但显然您不能在这种情况下使用 return:

(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

2 回答 2

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

除了检查函数的返回值之外,您还必须处理条件(使用例如handler-bindhandle ) 。

PS。调用length一个列表来检查它是否足够长并不是一个好主意 - 尽管在你的情况下,当列表保证很短时,这可能更多是一个风格问题。

聚苯乙烯。使用该词作为函数的名称不是一个好主意,handle因为 CL 具有包含它的函数(例如,handler-case)。除了使阅读您的代码的人感到困惑之外,这将使您的代码中的搜索变得复杂。

于 2013-08-22T16:12:11.087 回答
1

您不能调用RETURN从这样的函数返回。

您需要使用RETURN-FROM函数名称。但在这里它将从方法返回 - 而不是通用函数。

@sds 有答案。另一种是发出用户定义的条件并在其他地方处理它。使用旧代码catchthrow.

更复杂的任务是用户定义的方法组合。

于 2013-08-22T18:02:03.017 回答