11.8 方法组合机制 (Method Combination)
在标准方法组合中,只有最具体的主方法会被调用(虽然它可以通过 call-next-method
来调用其它方法)。但我们可能会想要把所有可用的主方法的结果汇总起来。
用其它组合手段来定义方法也是有可能的 ── 举例来说,一个返回所有可用主方法的和的通用函数。操作符 (Operator)方法组合可以这么理解,想像它是 Lisp 表达式的求值后的结果,其中 Lisp 表达式的第一个元素是某个操作符,而参数是按照具体性调用可用主方法的结果。如果我们定义 price
使用 +
来组合数值的通用函数,并且没有可用的 :around
方法,它会如它所定义的方式动作:
(defun price (&rest args)
(+ (apply 〈most specific primary method〉 args)
.
.
.
(apply 〈least specific primary method〉 args)))
如果有可用的 :around
方法的话,它们根据优先级决定,就像是标准方法组合那样。在操作符方法组合里,一个 around
方法仍可以通过 call-next-method
调用下个方法。然而主方法就不可以使用 call-next-method
了。
我们可以指定一个通用函数的方法组合所要使用的类型,借由在 defgeneric
调用里加入一个 method-combination
子句:
(defgeneric price (x)
(:method-combination +))
现在 price
方法会使用 +
方法组合;任何替 price
定义的 defmethod
必须有 +
来作为第二个参数。如果我们使用 price
来定义某些类型,
(defclass jacket () ())
(defclass trousers () ())
(defclass suit (jacket trousers) ())
(defmethod price + ((jk jacket)) 350)
(defmethod price + ((tr trousers)) 200)
则可获得一件正装的价钱,也就是所有可用方法的总和:
> (price (make-instance 'suit))
550
下列符号可以用来作为 defmethod
的第二个参数或是作为 defgeneric
调用中,method-combination
的选项:
+ and append list max min nconc or progn
你也可以使用 standard
,yields 标准方法组合。
一旦你指定了通用函数要用何种方法组合,所有替该函数定义的方法必须用同样的机制。而现在如果我们试着使用另个操作符( :before
或 after
)作为 defmethod
给 price
的第二个参数,则会抛出一个错误。如果我们想要改变 price
的方法组合机制,我们需要通过调用 fmakunbound
来移除整个通用函数。