common-lisp
CLOS - het Common Lisp Object System
Zoeken…
Een basis CLOS-les maken zonder ouders
Een CLOS-klasse wordt beschreven door:
- een naam
- een lijst met superklassen
- een lijst met slots
- verdere opties zoals documentatie
Elk slot heeft:
- een naam
- een initialisatieformulier (optioneel)
- een initialisatieargument (optioneel)
- een type (optioneel)
- een documentatie string (optioneel)
- accessor-, reader- en / of writer-functies (optioneel)
- verdere opties zoals toewijzing
Voorbeeld:
(defclass person ()
((name
:initform "Erika Mustermann"
:initarg :name
:type string
:documentation "the name of a person"
:accessor person-name)
(age
:initform 25
:initarg :age
:type number
:documentation "the age of a person"
:accessor person-age))
(:documentation "a CLOS class for persons with name and age"))
Een standaard afdrukmethode:
(defmethod print-object ((p person) stream)
"The default print-object method for a person"
(print-unreadable-object (p stream :type t :identity t)
(with-slots (name age) p
(format stream "Name: ~a, age: ~a" name age))))
Instanties maken:
CL-USER > (make-instance 'person)
#<PERSON Name: Erika Mustermann, age: 25 4020169AB3>
CL-USER > (make-instance 'person :name "Max Mustermann" :age 24)
#<PERSON Name: Max Mustermann, age: 24 4020169FEB>
Mixins en interfaces
Common Lisp heeft geen interfaces in de zin dat sommige talen (bijvoorbeeld Java) dat wel hebben, en er is minder behoefte aan dat type interface, aangezien Common Lisp meerdere overerving en generieke functies ondersteunt. Hetzelfde type patronen kan echter eenvoudig worden gerealiseerd met behulp van mixin-klassen. Dit voorbeeld toont de specificatie van een verzamelinginterface met verschillende overeenkomstige generieke functies.
;; 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)))
Een implementatie van de interface is slechts een klasse die de mixin als een van zijn superklassen heeft, en definities van de juiste generieke functies. (Merk op dit moment op dat de mixin-klasse echt alleen is voor het signaleren van de intentie dat de klasse de "interface" implementeert. Dit voorbeeld zou net zo goed werken met een paar generieke functies en documentatie die stelt dat er methoden zijn voor de functie voor de klas.)
;; 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))))
Ten slotte kunnen we zien hoe het gebruik van een instantie van de gesorteerde set- klasse eruit ziet bij het gebruik van de "interface" -functies:
(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)