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)


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow