2016-04-19 22 views
2

Ich möchte steuern, wie die Werte in Steckplätzen gespeichert werden und was zurückgegeben wird, wenn ich einen Steckplatz lese. Hier ist meine Klassendefinition:Common Lisp: Wie man Slot Accessoren übersteuert?

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

ich das Objekt auf diese Weise erstellen:

(setf obj1 (make-instance 'object)) 

Dies ist die Art und Weise ist, wie ich den Wert des Schlitzes erhalten name:

(name-access obj1) 

Und wie Ich setze einen neuen Wert:

(setf (name-access obj1) 'realname) 

Was ist der richtige Weg, um diese Accessor-Funktion (oder Methode) zu überschreiben, um einige Änderungen am Objekt vornehmen zu können (beim Schreiben) und um den zurückgegebenen Wert zu steuern?

Vielen Dank.

Antwort

5

können Sie definieren einfach manuell die Methoden für das Abrufen und Einstellen der Steckplätze:

(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 

Das Buch Practical Common Lisp in chapter 17 durch diese geht. Du solltest das lesen.

5

Sie können die Zugriffsmethoden durch DEFCLASS definiert erweitern:

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> 

Schreiben, mit einem :before Methode:

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

Lesen, mit einem :around Methode:

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> 

Beispiel :

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

Danke. Es scheint, dass es in einigen Gemeinschaften als ein besserer Weg angesehen wird, als den Accessor neu zu definieren. Aber ist es möglich, den Rückgabewert mit ': before' oder': around' Methoden zu ändern? –

+0

@ andrei-n: siehe Beispiel. Die around-Methode gibt zurück, was sie will. Die Vorher-Methode hat keinen Einfluss. –

+0

@ andrei-n Das Ändern des Rückgabewerts in einer Um-Methode birgt die Gefahr, dass später Unterklassen Probleme verursachen. Eine primäre Methode kann immer überschrieben werden, wenn ein anderes Verhalten erforderlich ist, aber es gibt keine einfache Möglichkeit, eine Um-Methode loszuwerden. Persönlich würde ich sagen, dass vor/um/nach-Methoden gut sind, wenn Sie einer vorhandenen Methode zusätzliche Funktionalität hinzufügen müssen, aber für die Kernfunktionalität sollte eine primäre Methode bevorzugt werden. – jkiiski