2013-08-22 9 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)) 

は、このアプローチでも正気で、はい、私はそれをどのように行うことができれば働くファッション?

答えて

4

私はあなたの代わりに:aroundメソッド修飾子を使用しなければならないと思います(私はすでに同じ結果とreturn-fromを試しました):

(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)の条件を処理する必要があります。

PS。リストにlengthを呼んで、それが十分に長いかどうかをチェックするのは良い考えではありません。あなたのケースでは、リストが短いと保証されているが、これはもっとスタイルの問題かもしれません。

PPS。 CLにはそれを含む関数があるので(例:handler-case)、関数の名前としてhandleという単語を使用することは非常に良い考えではありません。これにより、コード内の検索が複雑になり、コードを読んでいる人が混乱することになります。

1

RETURNを呼び出して、そのような関数から戻ることはできません。

RETURN-FROMを関数名に使用する必要があります。しかしここでは、ジェネリック関数ではなくメソッドから戻ることになります。

@sdsには答えがあります。もう1つは、ユーザー定義の条件を通知し、別の場所で処理することです。古いコードはcatchthrowです。

より複雑な作業は、ユーザー定義のメソッドの組み合わせになります。

関連する問題