2016-04-19 22 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 67 > (defmethod (setf name-access) :before (new-value (o1 object)) 
       (print "hi")) 
#<STANDARD-METHOD (SETF NAME-ACCESS) (:BEFORE) (T OBJECT) 40202283BB> 

閱讀,與:around方法:

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> 

實施例:

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方法返回任何它想要的。之前的方法沒有影響。 –

+0

@ andrei-n在around方法中更改返回值可能會在稍後導致子類出現問題。當需要不同的行爲時,主要方法總是可以被重寫,但是沒有簡單的方法來擺脫周圍方法。就個人而言,我會說,在必須爲現有方法添加額外功能之前/之後/之後方法很好,但定義主要方法應該是核心功能的首選。 – jkiiski