LISP - 对象系统(CLOS) - Lisp教程

Common Lisp通过几十年的面向对象编程的推进。但是,面向对象被并入是在它最后一阶段。

类的定义

defclass宏允许创建用户定义的类。它建立了一个类作为数据类型。它的语法如下:

(DEFCLASS class-name (superclass-name*)
  (slot-description*)
  class-option*)

插槽是存储数据变量或字段。

slot-description形式(插槽名称插槽选项*),其中每个选项是一个关键字后跟一个名字,表达式和其他选项。最常用的槽选项是:

  • :accessor 函数名称

  • :initform 表达式

  • :initarg 符号

例如,让我们定义一个Box类,有三个槽的长度,广度和高度。

(defclass Box () 
(length 
breadth 
height))

提供访问和读/写控制到一个插槽

除非有插槽可以访问,读取或写入的值,类是好看不中用。

当定义一个类可以为每个插槽指定访问。例如,把我们的Box类:

(defclass Box ()
  ((length :accessor length)
   (breadth :accessor breadth)
   (height :accessor height)))

也可以读取和写入一个插槽指定单独的访问器的名称。

(defclass Box ()
    ((length :reader get-length :writer set-length)
     (breadth :reader get-breadth :writer set-breadth)
     (height :reader get-height :writer set-height)))

类创建实例

通用函数make-instance创建并返回一个类的新实例。

它的语法如下:

(make-instance class {initarg value}*)

示例

让我们创建一个Box类,有三个插槽,长度,宽度和高度。我们将使用三个插槽存取到这些字段设置的值。

创建一个名为main.lisp一个新的源代码文件,并在其中输入如下代码:

(defclass box ()
  ((length :accessor box-length)
   (breadth :accessor box-breadth)
   (height :accessor box-height)))
(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))

当执行代码,它返回以下结果:

Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5

定义一个类的方法

defmethod宏允许在类中定义一个方法。下面的示例扩展Box类包含一个方法名为volume。

创建一个名为main.lisp一个新的源代码文件,并在其中输入如下代码:

(defclass box ()
  ((length :accessor box-length)
   (breadth :accessor box-breadth)
   (height :accessor box-height)
   (volume :reader volume)))

; method calculating volume   

(defmethod volume ((object box))
  (* (box-length object) (box-breadth object)(box-height object)))

 ;setting the values 

(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)

; displaying values

(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))
(format t "Volume of the Box is ~d~%" (volume item))

当执行代码,它返回以下结果:

Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5
Volume of the Box is 500

继承

LISP允许在另一个对象来定义一个对象。这就是所谓的继承。可以通过添加功能,新的或不同的创建派生类。派生类继承了父类的功能。

下面的例子说明了这一点:

示例

创建一个名为main.lisp一个新的源代码文件,并在其中输入如下代码:

(defclass box ()
  ((length :accessor box-length)
   (breadth :accessor box-breadth)
   (height :accessor box-height)
   (volume :reader volume)))
; method calculating volume   
(defmethod volume ((object box))
  (* (box-length object) (box-breadth object)(box-height object)))

;wooden-box class inherits the box class  
(defclass wooden-box (box)
((price :accessor box-price)))

 ;setting the values 
(setf item (make-instance 'wooden-box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(setf (box-price item) 1000)

; displaying values

(format t "Length of the Wooden Box is ~d~%" (box-length item))
(format t "Breadth of the Wooden Box is ~d~%" (box-breadth item))
(format t "Height of the Wooden Box is ~d~%" (box-height item))
(format t "Volume of the Wooden Box is ~d~%" (volume item))
(format t "Price of the Wooden Box is ~d~%" (box-price item))

当执行代码,它返回以下结果:

Length of the Wooden Box is 10
Breadth of the Wooden Box is 10
Height of the Wooden Box is 5
Volume of the Wooden Box is 500
Price of the Wooden Box is 1000