Представьте себе некоторый базовый класс pgj-model
со многими определенными на нем методами, но без слотов. Теперь рассмотрим:Как использовать CLOS для типов, а не для экземпляров?
(defclass cat (pgj-model)())
(let ((cat (make-instance 'cat)))
(ensure-backend cat)
(insert cat (obj "name" "Joey" "coat" "tabby")))
Если мы хотим, чтобы настроить новый класс cat
мы можем специализироваться метод следующим образом:
(defmethod insert ((model cat) (object hash-table))
;; Do something interesting
)
Это все очень хорошо. Но ни pgj-model
, ни cat
не имеют слотов, они меньше. Это по дизайну, поскольку меня интересуют только их как типы Lisp, на которые можно специализировать методы. Таким образом, кажется, раздражает/запутывает создание экземпляра класса cat
везде, где вы хотите назвать такие методы.
Одна идея состоит в том, чтобы сделать:
(defparameter *cat* (make-instance 'cat)) ; There can be only one...
...
(insert *cat* (obj "name" "Joey" "coat" "tabby"))
Другой специализироваться дополнительный метод на всех моих общих функций, как так:
(defmethod insert ((model symbol) object)
(insert (make-instance model) object))
(insert 'cat (obj "name" "Joey" "coat" "tabby"))
, который, кажется нормально, но 1) может запутать пользователей, 2) раздувает общую функцию с шаблоном и 3) добавляет некоторые накладные расходы для каждого вызова метода.
Другие предложения?
Отличный материал. По * глобальным функциям считывателя * вы имеете в виду что-то вроде '(let (cat) (defun cat() (если кошка кошка (setf cat (make-instance 'cat)))))'? Почему это лучше, чем глобальная переменная? – gtod
Потому что вы можете реализовать его, однако вы хотите позже, не меняя код, который его использует. Если позже вы решите, что необходимо использовать глобальную/динамическую переменную (например, '* cat *'), чтобы ее значение зависело от текущего потока или что примитивы синхронизации (сравнение и обмен) не работают с локальными переменными , к нему все равно будет обращаться с помощью '(cat)'. Если дополнительная скобка беспокоит вас, вы можете '(define-symbol-macro cat (cat))' и просто использовать 'cat'. – acelent
Я бы оставил функцию в любом случае. В зависимости от вашей реализации я объявлял бы функцию inline или определял для нее макрос компилятора, если вы не ожидаете переопределить функцию во время выполнения (например, путем загрузки патчей). – acelent