面向对象

在多数 OOP 系统中,方法属于类。在 Common Lisp 中,方法是通用函数的实例,这些函数不仅可以分派到第一个参数,还可以分派到每个参数。这意味着函数,而不是类,是主要的驱动力。

通用函数和方法

我们使用 defgeneric 声明一个通用函数

(defgeneric description (object)
  (:documentation "Return a description of an object."))

我们使用 defmethod 声明该函数的方法

(defmethod description ((object integer))
  (format nil "The integer ~D" object))

(defmethod description ((object float))
  (format nil "The float ~3,3f" object))

我们可以在 REPL 中测试它们

CL-USER> (description 10)
"The integer 10"

CL-USER> (description 3.14)
"The float 3.140"

(defclass vehicle ()
  ((speed :accessor vehicle-speed
          :initarg :speed
          :type real
          :documentation "The vehicle's current speed."))
  (:documentation "The base class of vehicles."))

当超类列表为空时,使用默认基类 standard-class。你可以更改它,但这是一项高级主题。

(defclass bicycle (vehicle)
  ((mass :reader bicycle-mass
         :initarg :mass
         :type real
         :documentation "The bike's mass."))
  (:documentation "A bicycle."))

(defclass canoe (vehicle)
  ((rowers :reader canoe-rowers
           :initarg :rowers
           :initform 0
           :type (integer 0)
           :documentation "The number of rowers."))
  (:documentation "A canoe."))

实例化

CL-USER> (defparameter canoe (make-instance 'canoe
                                            :speed 10
                                            :rowers 6))
CANOE

CL-USER> (class-of canoe)
#<STANDARD-CLASS COMMON-LISP-USER::CANOE>

CL-USER> (canoe-rowers canoe)
6

CL-USER> (vehicle-speed canoe)
10

我们可以使用 describe 获取有关类的信息

CL-USER> (describe 'canoe)
COMMON-LISP-USER::CANOE
  [symbol]

CANOE names the standard-class #<STANDARD-CLASS
                                 COMMON-LISP-USER::CANOE>:
  Documentation:
    A canoe.
  Direct superclasses: VEHICLE
  No subclasses.
  Not yet finalized.
  Direct slots:
    ROWERS
      Type: (INTEGER 0)
      Initargs: :ROWERS
      Initform: 0
      Readers: CANOE-ROWERS
      Documentation:
       The number of rowers.