现在 combine 有一个方法。若我们在此时调用 combine ,我们会获得由传入的两个参数所组成的一个列表:

    1. > (combine 'a 'b)
    2. (A B)

    到现在我们还没有做任何一般函数做不到的事情。一个通用函数不寻常的地方是,我们可以继续替它加入新的方法。

    首先,我们定义一些可以让新的方法引用的类别:

    1. (defclass stuff () ((name :accessor name :initarg :name)))
    2. (defclass ice-cream (stuff) ())
    3. (defclass topping (stuff) ())

    这里定义了三个类别: stuff ,只是一个有名字的东西,而 ice-creamtoppingstuff 的子类。

    现在下面是替 combine 定义的第二个方法:

    1. (defmethod combine ((ic ice-cream) (top topping))
    2. (format nil "~A ice-cream with ~A topping."
    3. (name ic)

    在这次 defmethod 的调用中,参数被特化了 (specialized):每个出现在列表里的参数都有一个类别的名字。一个方法的特化指出它是应用至何种类别的参数。我们刚定义的方法仅能在传给 combine 的参数分别是 ice-cream 与 的实例时。

    但使用其他参数时,我们会得到我们第一次定义的方法:

    1. > (combine 23 'skiddoo)
    2. (23 SKIDDOO)

    因为第一个方法的两个参数皆没有特化,它永远只有最低优先权,并永远是最后一个调用的方法。一个未特化的方法是一个安全手段,就像 case 表达式中的 otherwise 子句。

    一个方法中,任何参数的组合都可以特化。在这个方法里,只有第一个参数被特化了:

    1. (defmethod combine ((ic ice-cream) x)
    2. (format nil "~A ice-cream with ~A."
    3. (name ic)
    4. x))

    若我们用一个 ice-cream 的实例以及一个 topping 的实例来调用 combine ,我们仍然得到特化两个参数的方法,因为它是最具体的那个:

    1. > (combine (make-instance 'ice-cream :name 'grape)
    2. (make-instance 'topping :name 'marshmallow))

    然而若第一个参数是 ice-cream 而第二个参数不是 topping 的实例的话,我们会得到刚刚上面所定义的那个方法:

    当一个通用函数被调用时,参数决定了一个或多个可用的方法 (applicable methods)。如果在调用中的参数在参数的特化约定内,我们说一个方法是可用的。

    在前面的例子里,很容易看出哪个是最具体的可用方法,因为所有的对象都是单继承的。一个 ice-cream 的实例是,按顺序来, , stuffstandard-object , 以及 t 类别的成员。

    方法不需要在由 defclass 定义的类别层级来做特化。他们也可以替类型做特化(更精准的说,可以反映出类型的类别)。以下是一个给 combine 用的方法,对数字做了特化:

    1. (defmethod combine ((x number) (y number))
    2. (+ x y))

    方法甚至可以对单一的对象做特化,用 eql 来决定:

    1. (defmethod combine ((x (eql 'powder)) (y (eql 'spark)))
    2. 'boom)

    单一对象特化的优先级比类别特化来得高。

    方法可以像一般 Common Lisp 函数一样有复杂的参数列表,但所有组成通用函数方法的参数列表必须是一致的 (congruent)。参数的数量必须一致,同样数量的选择性参数(如果有的话),要嘛一起使用 &rest 或是 &key 参数,或者一起不要用。下面的参数列表对是全部一致的,

    1. (x) (a)
    2. (x &optional y) (a &optional b)
    3. (x y &rest z) (a b &key c)
    4. (x y &key z) (a b &key c d)

    而下列的参数列表对不是一致的:

    1. 'kaboom)

    我们重定义了当 combine 方法的参数是 powder 与 时, combine 方法干了什么事儿。