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

ただし、より「リピー」なアプローチは、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-bindなどを使用して) 条件を処理する必要がありますhandle

PS。リストが十分に長いことを確認するためにリストを呼び出すlengthことはあまり良い考えではありません-あなたの場合、リストが短いことが保証されている場合、これはスタイルの問題である可能性があります。

PPS。handleCL にはこの単語を含む関数があるため (たとえば、 ) 、この単語を関数の名前として使用することはあまり良い考えではありませんhandler-case。これにより、コードを読む人が混乱するだけでなく、コード内の検索が複雑になります。

于 2013-08-22T16:12:11.087 に答える