common-lisp
CLOS - el sistema de objetos Common Lisp
Buscar..
Creando una clase básica de CLOS sin padres
Una clase CLOS es descrita por:
- un nombre
- una lista de superclases
- una lista de ranuras
- otras opciones como documentación
Cada ranura tiene:
- un nombre
- un formulario de inicialización (opcional)
- un argumento de inicialización (opcional)
- un tipo (opcional)
- una cadena de documentación (opcional)
- Funciones de acceso, lector y / o escritor (opcional)
- otras opciones como la asignación
Ejemplo:
(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"))
Un método de impresión predeterminado:
(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))))
Creando instancias:
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 e interfaces
Common Lisp no tiene interfaces en el sentido en que lo hacen algunos idiomas (por ejemplo, Java), y hay menos necesidad de ese tipo de interfaz, dado que Common Lisp admite funciones de herencia múltiple y genéricas. Sin embargo, el mismo tipo de patrones se puede realizar fácilmente usando clases de mezcla. Este ejemplo muestra la especificación de una interfaz de colección con varias funciones genéricas correspondientes.
;; 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)))
Una implementación de la interfaz es solo una clase que tiene la mezcla como una de sus súper clases y definiciones de las funciones genéricas apropiadas. (En este punto, observe que la clase mixin es realmente solo para indicar la intención de que la clase implemente la "interfaz". Este ejemplo funcionaría igual de bien con algunas funciones genéricas y documentación que indica que hay métodos en la función para la clase.)
;; 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))))
Finalmente, podemos ver cómo se ve una instancia de la clase de conjuntos ordenados cuando se usan las funciones de "interfaz":
(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)