2016-04-19 5 views
2

値をスロットに保存する方法と、スロットを読み取ったときに返される値を制御したいと考えています。ここに私のクラス定義は次のとおりです。Common Lisp:スロットアクセサを無効にする方法は?

(defclass object() 
    ((name :accessor name-access 
     :initform 'noname 
     :initarg :name) 
    (value :accessor value-access 
     :initform 10 
     :initarg :value))) 

私はオブジェクトをこのように作成します。

(setf obj1 (make-instance 'object)) 

これは私がスロットnameの値を取得する方法の方法です:

(name-access obj1) 

そして、どのように新しい値を設定しました:

(setf (name-access obj1) 'realname) 

オブジェクト(書き込み時)に何らかの変更を加えて戻り値を制御できるようにするために、このアクセサ関数(またはメソッド)をオーバーライドする正しい方法は何ですか?

ありがとうございます。

答えて

5

あなただけ手動でスロットを取得および設定するためのメソッドを定義することができます。

(defclass foo() 
    ((name :initform 'noname 
     :initarg :name))) 

(defgeneric name-access (foo) 
    (:method ((foo foo)) 
    (format t "~&Getting name.~%") 
    (slot-value foo 'name))) 

(defgeneric (setf name-access) (name foo) 
    (:method (name (foo foo)) 
    (format t "~&Setting a new name.~%") 
    (setf (slot-value foo 'name) name))) 

(defparameter *foo* (make-instance 'foo)) 
(name-access *foo*) 
; Getting name. 
;=> NONAME 

(setf (name-access *foo*) 'some-name) 
; Setting a new name. 
;=> SOME-NAME 

(name-access *foo*) 
; Getting name. 
;=> SOME-NAME 

ブックPractical Common Lispchapter 17にこれらを通過します。あなたはそれを読むべきです。

5

あなたはDEFCLASSによって定義されたアクセサメソッドを拡張することができる:

CL-USER 66 > (defclass object() 
       ((name :accessor name-access 
         :initform 'noname 
         :initarg :name) 
       (value :accessor value-access 
         :initform 10 
         :initarg :value))) 
#<STANDARD-CLASS OBJECT 4220014953> 

書き込み、:before方法使用:

CL-USER 68 > (defmethod name-access :around ((o1 object)) 
       (let ((name (call-next-method))) 
       (values name (length (symbol-name name))))) 
#<STANDARD-METHOD NAME-ACCESS (:AROUND) (OBJECT) 4020061213> 

例::around方法に

CL-USER 67 > (defmethod (setf name-access) :before (new-value (o1 object)) 
       (print "hi")) 
#<STANDARD-METHOD (SETF NAME-ACCESS) (:BEFORE) (T OBJECT) 40202283BB> 

読書を:

CL-USER 69 > (let ((o1 (make-instance 'object))) 
       (setf (name-access o1) 'foobar) 
       (name-access o1)) 

"hi"  ; side effect 
FOOBAR ; return value 1 
6  ; return value 2 
+0

ありがとうございました。いくつかのコミュニティではアクセサーを再定義するよりも良い方法だと思われます。しかし、 ':before'や':around'メソッドで返された値を変更することは可能ですか? –

+0

@ andrei-n:例を参照してください。 aroundメソッドは、必要なものを返します。 beforeメソッドは影響を与えません。 –

+0

@ andrei-n aroundメソッドの戻り値を変更すると、後でサブクラスに問題が発生する危険性があります。基本的な方法は、異なる動作が必要なときに常に上書きできますが、周囲のメソッドを取り除く簡単な方法はありません。個人的には、既存のメソッドに余分な機能を追加する必要があるときに、before/around/after -methodsが良いと言っていますが、主要な機能のためにはプライマリメソッドを定義することをお勧めします。 – jkiiski

関連する問題