我有一组表示必须处理的消息的类。但是处理者的开放点数量有限。因此,处理消息对象的处理程序的任何“调度”必须首先检查是否存在空闲点。
如果有 - >调度。
如果没有 - >不发送和返回相应的消息
由于这部分代码在任何调度方法中都是相同的,我认为最好使用方法组合工具来强制执行,但我无法弄清楚如何。
在我目前的代码库中,我尝试使用: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
使用相同的结果)
答案 0 :(得分:4)
我认为您应该使用:around
方法限定符:
(defmethod handle :around ((message message))
(if (cddr *open-handler*)
:full
(call-next-method)))
然而,更“懒散”的做法是使用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)。
PS。在列表上调用length
以检查它是否足够长并不是一个好主意 - 尽管在您的情况下,当保证列表很短时,这可能更像是样式问题。
PPS。使用单词handle
作为函数名称不是一个好主意,因为CL具有包含它的函数(例如,handler-case
)。除了让阅读代码的人感到困惑之外,这会使代码中的搜索变得复杂。
答案 1 :(得分:1)
你无法调用RETURN
从这样的函数返回。
您需要将RETURN-FROM
与函数名称一起使用。但是这里它将从方法返回 - 而不是泛型函数。
@sds有一个答案。另一个是发信号通知用户定义的条件并在其他地方处理它。旧代码使用catch
和throw
。
更复杂的任务是用户定义的方法组合。