Mixins 和介面
Common Lisp 在某些語言(例如 Java)的意義上沒有介面,並且由於 Common Lisp 支援多重繼承和泛型函式,因此對該型別介面的需求較少。但是,使用 mixin 類可以輕鬆實現相同型別的模式。此示例顯示了具有多個相應泛型函式的集合介面的規範。
;; Specification of the COLLECTION "interface"
(defclass collection () ()
(:documentation "A collection mixin."))
(defgeneric collection-elements (collection)
(:documentation "Returns a list of the elements in the collection."))
(defgeneric collection-add (collection element)
(:documentation "Adds an element to the collection."))
(defgeneric collection-remove (collection element)
(:documentation "Removes the element from the collection, if it is present."))
(defgeneric collection-empty-p (collection)
(:documentation "Returns whether the collection is empty or not."))
(defmethod collection-empty-p ((c collection))
"A 'default' implementation of COLLECTION-EMPTY-P that tests
whether the list returned by COLLECTION-ELEMENTS is the empty
list."
(endp (collection-elements c)))
介面的實現只是一個將 mixin 作為其超類之一的類,以及相應泛型函式的定義。 (此時,請注意,mixin 類實際上僅用於表示類實現介面的意圖。這個示例也適用於一些通用函式和文件,這些函式和文件宣告函式上有方法類。)
;; Implementation of a sorted-set class
(defclass sorted-set (collection)
((predicate
:initarg :predicate
:reader sorted-set-predicate)
(test
:initarg :test
:initform 'eql
:reader sorted-set-test)
(elements
:initform '()
:accessor sorted-set-elements
;; We can "implement" the COLLECTION-ELEMENTS function, that is,
;; define a method on COLLECTION-ELEMENTS, simply by making it
;; a reader (or accessor) for the slot.
:reader collection-elements)))
(defmethod collection-add ((ss sorted-set) element)
(unless (member element (sorted-set-elements ss)
:test (sorted-set-test ss))
(setf (sorted-set-elements ss)
(merge 'list
(list element)
(sorted-set-elements ss)
(sorted-set-predicate ss)))))
(defmethod collection-remove ((ss sorted-set) element)
(setf (sorted-set-elements ss)
(delete element (sorted-set-elements ss))))
最後,我們可以看到在使用 interface
函式時使用 sorted-set 類的例項是什麼樣的 :
(let ((ss (make-instance 'sorted-set :predicate '<)))
(collection-add ss 3)
(collection-add ss 4)
(collection-add ss 5)
(collection-add ss 3)
(collection-remove ss 5)
(collection-elements ss))
;; => (3 4)