common-lisp
CLOS - das Common-Lisp-Objektsystem
Suche…
Erstellen einer CLOS-Grundklasse ohne Eltern
Eine CLOS-Klasse wird beschrieben durch:
- ein Name
- eine Liste von Superklassen
- eine Liste von Slots
- weitere Optionen wie Dokumentation
Jeder Slot hat:
- ein Name
- ein Initialisierungsformular (optional)
- ein Initialisierungsargument (optional)
- ein Typ (optional)
- eine Dokumentationszeichenfolge (optional)
- Zugriffs-, Lese- und / oder Schreibfunktionen (optional)
- weitere Optionen wie Zuordnung
Beispiel:
(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"))
Eine Standarddruckmethode:
(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))))
Instanzen erstellen:
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 und Schnittstellen
Common Lisp hat keine Schnittstellen in dem Sinne, wie dies einige Sprachen (z. B. Java) tun, und diese Art von Schnittstelle ist weniger erforderlich, da Common Lisp mehrere Vererbungsfunktionen und generische Funktionen unterstützt. Dieselbe Art von Mustern kann jedoch leicht mit Mixin-Klassen realisiert werden. Dieses Beispiel zeigt die Spezifikation einer Erfassungsschnittstelle mit mehreren entsprechenden generischen Funktionen.
;; 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)))
Eine Implementierung der Schnittstelle ist nur eine Klasse, die das Mixin als eine ihrer Superklassen und Definitionen der entsprechenden generischen Funktionen enthält. (An dieser Stelle ist zu beachten, dass die mixin-Klasse wirklich nur zum Signalisieren der Absicht dient, dass die Klasse das "Interface" implementiert. Dieses Beispiel würde genauso gut mit einigen generischen Funktionen und Dokumentation funktionieren, die besagen, dass es Methoden für die Funktion gibt die Klasse.)
;; 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))))
Schließlich können wir sehen, wie die Verwendung einer Instanz der Sortiersatzklasse bei Verwendung der "Schnittstellen" -Funktionen aussieht:
(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)