Tod*_*odd 3 lisp common-lisp clos
我是 CLOS 新手。这是我的例子:
(defclass box ()
((length :accessor box-length :initform 0 :initarg :bxl)
(breath :accessor box-breadth :initform 0 :initarg :bxb)
(height :accessor box-height :initform 0 :initarg :bxh)
(volume :reader volume :initform 0 :initarg :v)))
Run Code Online (Sandbox Code Playgroud)
构造函数是:
(defun make-box (l b h)
(make-instance 'box :bxl l :bxb b :bxh h :v (* l b h)))
Run Code Online (Sandbox Code Playgroud)
所以当我像这样创建“盒子”的实例时:
; make a box, 4 x 3 x 2
(defparameter my-box (make-box 4 3 2))`
Run Code Online (Sandbox Code Playgroud)
它按我的预期工作。我可以“描述”我的盒子并得到:
(describe my-box)
#<BOX {100363F493}>
[standard-object]
Slots with :INSTANCE allocation:
LENGTH = 4
BREATH = 3
HEIGHT = 2
VOLUME = 24
Run Code Online (Sandbox Code Playgroud)
现在,问题来了。如果我像这样更新“高度”:
(setf (box-height my-box) 5)
Run Code Online (Sandbox Code Playgroud)
如何让这个“setf”自动更新“volume”插槽?
那么 VOLUME 将更改为(* 4 3 5) = 60?
实现此目的的一种方法是在setf各种访问器的方法上使用 after 方法。所以:
(defmethod (setf box-length) :after (length (b box))
(with-slots (breadth height volume) b
(setf volume (* length breadth height))))
Run Code Online (Sandbox Code Playgroud)
这也可以通过 before 方法来完成,但如果您使用通用的“更新卷”函数,您需要使用 after 方法来避免存储插槽两次,或者setf完全自己定义访问器的侧面。
另一种当然更简单的方法是根本没有卷槽,而是计算它:
(defclass box ()
((length :accessor box-length :initform 0 :initarg :bxl)
(breath :accessor box-breadth :initform 0 :initarg :bxb)
(height :accessor box-height :initform 0 :initarg :bxh)))
(defgeneric volume (object))
(defmethod volume ((b box))
(* (box-length b) (box-breadth b) (box-height b)))
Run Code Online (Sandbox Code Playgroud)
显然,其他类仍然可以拥有卷槽,并且volume通用函数上的方法可以访问该槽:协议是相同的。
您甚至可以通过为esdescribe定义方法或仅定义 after 方法来报告体积。特别是在后一种情况下,您可能必须努力使格式与您的实现的行为一致。这是一个恰好适合我通常的实现(LispWorks)的方法:describe-objectboxdescribe
(defmethod describe-object :after ((b box) stream)
(format stream "~& and volume ~D~%" (volume b)))
Run Code Online (Sandbox Code Playgroud)
现在
> (describe (make-instance 'box))
#<box 801001147B> is a box
length 0
breath 0
height 0
and volume 0
Run Code Online (Sandbox Code Playgroud)