Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Pol_Grem_-_ANSI_Common_Lisp_High_tech_-_2012.pdf
Скачиваний:
39
Добавлен:
12.03.2016
Размер:
4.85 Mб
Скачать

190

Глава 11. CLOS

Если­ зада­но­ необя­за­тель­ное­ свойст­во­ :documentation, то оно долж­но со­ держать­ строку­ описа­ния­ данно­го­ слота­. Зада­вая­ :type, вы обязуе­тесь­ обеспе­чить­ то, что слот будет­ содер­жать­ лишь значе­ния­ задан­но­го­ типа­. Декла­ра­ции­ типов­ будут­ рассмот­ре­ны­ в разделе 13.3.

11.4. Суперклассы

Второй­ аргу­мент­ defclass явля­ет­ся­ списком­ супер­клас­сов­. От них класс насле­ду­ет­ набор­ слотов­. Так, если­ мы опре­де­лим­ класс screen-circle как подкласс­ circle и graphic:

(defclass graphic ()

((color :accessor graphic-color :initarg :color) (visible :accessor graphic-visible :initarg :visible

:initform t)))

(defclass screen-circle (circle graphic)

())

то экзем­п­ля­ры­ screen-circle будут­ иметь четы­ре­ слота,­ по два от каждо­­ го класса­-роди­те­ля­. И при этом не нуж­но созда­вать­ какие­-либо­ новые­ слоты­ как его собст­вен­­ные – подкласс­ screen-circle созда­ет­ся­ лишь для объеди­не­ния­ возмож­но­стей­ двух классов­ circle и graphic.

Пара­мет­ры­ слотов­ (:accessor, :initarg и другие)­ насле­ду­ют­ся­ вместе­ с са­ мими­ слота­ми­ и рабо­та­ют­ так же, как если­ бы они исполь­зо­ва­лись­ для экзем­п­ля­ров­ circle или graphic:

> (graphic-color (make-instance ’screen-circle

:color ’red :radius 3))

RED

Тем не менее­ в опре­де­ле­нии­ класса­ мож­но указы­­вать неко­то­рые­ пара­­ метры­ для насле­дуе­мых­ слотов,­ напри­мер­ :initform:

(defclass screen-circle (circle graphic) ((color :initform ’purple)))

Теперь­ экзем­п­ля­ры­ screen-circle будут­ пурпур­ны­ми­ по умолча­нию:­

> (graphic-color (make-instance ’screen-color)) PURPLE

11.5. Предшествование

Мы позна­ко­ми­лись­ с ситуа­ци­ей,­ когда­ классы­ могут­ иметь несколь­ко­ супер­клас­сов­. Если­ для неко­то­рых­ супер­клас­сов­ опре­де­лен­ метод­ с од­ ним и тем же именем,­ Лисп должен­ выбрать­ один из них, руко­во­дству­­ ясь прави­лом­ предше­ст­во­ва­ния­.

Для каждо­го­ класса­ суще­ст­ву­ет­ список­ предше­ст­во­ва­ния­ – поря­док­ сле­ дова­ния­ классов­ от наибо­лее­ специ­фич­но­го­ до наиме­нее­ специ­фич­но­го,­ включая­ рассмат­ри­вае­мый­ класс. В приме­рах,­ приве­ден­ных­ ранее,­ по­

11.5. Предшествование

191

рядок­ предше­ст­во­ва­ния­ был триви­аль­ным,­ одна­ко­ он может­ услож­нить­­ ся в больших­ програм­мах­. Вот пример­ более­ сложной­ иерар­хии­ классов:­

(defclass sculpture () (height width depth)) (defclass statue (sculpture) (subject)) (defclas metalwork () (metal-type)) (defclass casting (metalwork) ())

(defclass cast-statue (statue casting) ())

Граф, представ­ляю­щий­ класс cast-statue и его супер­клас­сы,­ изобра­жен­ на рис. 11.3.

 

t

 

standard object

sculpture

metalwork

statue

casting

cast statue

Рис. 11.3. Иерар­хия­ классов­

Чтобы­ по­строить­ такой­ граф, не­обхо­ди­мо­ начать­ с узла,­ соот­вет­ст­вую­­ щего­ классу,­ и двигать­ся­ снизу­-вверх. Ребра,­ направ­лен­ные­ вверх, свя­ зыва­ют­ класс с прямы­ми­ супер­клас­са­ми,­ кото­рые­ распо­ла­га­ют­ся­ слева­- напра­во­ в соот­вет­ст­вии­ с поряд­ком­ соот­вет­ст­вую­щих­ вызо­вов­ defclass­. Эта проце­ду­ра­ повто­ря­ет­ся­ до тех пор, пока­ для каждо­го­ класса­ будет­ суще­ст­во­вать­ лишь один супер­класс ­– standard-object. Это справед­ли­во­ для классов,­ в опре­де­ле­нии­ кото­рых­ второй­ аргу­мент­ был (). Узел, соот­­ ветст­вую­щий­ каждо­му­ тако­му­ классу,­ связан­ с узлом­ standard­-object, а он в свою очередь ­– с классом­ t. Проде­лав­ подоб­ные­ опера­ции,­ мы по­ лучим­ граф, изобра­жен­ный­ на рис. 11.3.

Теперь­ мы можем­ соста­вить­ список­ предше­ст­во­ва­ния:­

1.Начи­на­ем­ с низа­ графа­.

2.Движем­ся­ вверх, всегда­ выби­рая­ левое­ из ранее­ непрой­ден­ных­ ребер­.

192

Глава 11. CLOS

3.Если обна­ру­жи­ва­ет­ся,­ что мы пришли­ к узлу,­ к кото­ро­му­ ведет­ реб­ ро справа,­ то отма­ты­ва­ем­ все пере­ме­ще­ния­ до тех пор, пока­ не вер­ немся­ в узел с други­ми­ непрой­ден­ны­ми­ ребра­ми­. Вернув­шись,­ по­ вторя­ем­ шаг 2.

4.Завер­ша­ем­ проце­ду­ру­ по дости­же­нии­ t. Поря­док,­ в кото­ром­ каждый­ узел был впервые­ посе­щен,­ опре­де­ля­ет­ список­ предше­ст­во­ва­ния­.

В пункте­ 3 упоми­на­ет­ся­ важ­ный момент:­ ни один класс не может­ нахо­­ диться­ в списке­ предше­ст­во­ва­ния­ до любо­го­ из его подклас­сов­.

Стрелки­ на рис. 11.3 пока­зы­­вают­ направ­ле­ние­ обхо­да­. Список­ предше­­ ство­ва­ния­ нашей­ иерар­хии­ будет­ следую­щим:­ cast-statue, statue, sculp­ ture, casting, metalwork, standard-object, t. Иногда­ поло­же­ние­ класса­ в та­ ком списке­ назы­­вают­ его специ­фич­но­стью­. Классы­ распо­ло­же­ны­ в нем по убы­ванию­ специ­фич­но­сти­.

По списку­ предше­ст­во­ва­ния­ можно­ опре­де­лить,­ какой­ метод­ необ­хо­ди­­ мо при­менить­ при вызо­ве­ обобщен­ной­ функции­. Этот процесс­ рассмат­­ рива­ет­ся­ в следую­щем­ разде­ле­. Поря­док­ следо­ва­ния,­ связан­ный­ с вы­ бором­ насле­дуе­мо­го­ слота,­ нами­ пока­ не рассмат­ри­вал­ся­. Соот­вет­ст­­ вующие­ прави­ла­ его опре­де­ле­ния­ можно­ найти­ на стр. 428.°

11.6. Обобщенные функции

Обобщен­ной­ функци­ей­ назы­ва­ют­ функцию,­ постро­ен­ную­ из одно­го­ или несколь­ких­ мето­дов­. Мето­ды­ опре­де­ля­ют­ся­ через­ опера­тор­ defmethod­, кото­рый­ напо­ми­на­ет­ defun:

(defmethod combine (x y) (list x y))

На данный­ момент­ combine имеет­ один метод,­ и ее вызов­ постро­ит­ спи­ сок из двух аргу­мен­тов:­

> (combine ’a ’b) (A B)

Пока­ что мы не сдела­ли­ ниче­го,­ с чем не справи­лась­ бы обычная­ функ­ ция. Одна­ко­ отли­чия­ станут­ замет­ны­ при добав­ле­нии­ еще одно­го­ мето­да­.

Для нача­ла­ созда­дим­ несколь­ко­ классов,­ с кото­ры­­ми будут­ рабо­тать­ на­ ши мето­ды:­

(defclass stuff () ((name :accessor name :initarg :name))) (defclass ice-cream (stuff) ())

(defclass topping (stuff) ())

Мы опре­де­ли­ли­ три класса:­ stuff, имеющий­ слот name, а также­ ice-cream и topping, являю­щие­ся­ подклас­са­ми­ stuff.

Теперь­ созда­дим­ второй­ метод­ для combine:

(defmethod combine ((ic ice-cream) (top topping)) (format nil "~A ice-cream with ~A topping."

11.6. Обобщенные функции

193

(name ic) (name top)))

В этом вызо­ве­ defmethod пара­мет­ры­ конкре­ти­зи­ро­ва­ны­: каждый­ из них появ­ля­ет­ся­ в списке­ с именем­ класса­. Конкре­ти­за­ции­ мето­да­ указы­­ва­ ют на типы­ аргу­мен­тов,­ к кото­рым­ он при­меним­. Приве­ден­ный­ метод­ может­ исполь­зо­вать­ся­ только­ с опре­де­лен­­ными­ аргу­мен­та­ми:­ первым­ аргу­мен­том­ должен­ быть экзем­п­ляр­ ice-cream, а вторым ­– экзем­п­ляр­ topping.

Как Лисп опре­де­ля­ет,­ какой­ метод­ вызвать?­ Из тех, что удовле­тво­ря­ют­ огра­ни­че­ни­ям­ на классы,­ будет­ выбран­ наибо­лее­ специ­фич­ный­. Это зна­ чит, напри­мер,­ что для аргу­мен­тов,­ представ­­ляющих­ классы­ ice-cream и topping соот­вет­ст­вен­­но, будет­ при­менен­ послед­ний­ опре­де­лен­­ный на­ ми метод:­

> (combine (make-instance ’ice-cream :name ’fig) (make-instance ’topping :name ’treacle))

"FIG ice-cream with TREACLE topping."

Для любых­ других­ аргу­мен­тов­ будет­ приме­нен­ наш первый­ метод:­

> (combine 23 ’skiddoo) (23 SKIDDOO)

Ни один из аргу­мен­тов­ этого­ мето­да­ не был конкре­ти­зи­ро­ван,­ поэто­му­ он имеет­ наимень­ший­ приори­тет­ и будет­ вызван­ лишь тогда,­ когда­ ни один другой­ метод­ не подой­дет­. Такие­ мето­ды­ служат­ своего­ рода­ запас­­ ным вари­ан­том,­ подоб­но­ ключу­ otherwise в case-выра­же­нии­.

Любая­ комби­на­ция­ пара­мет­ров­ мето­да­ может­ быть конкре­ти­зи­ро­ва­на­. В следую­щем­ мето­де­ огра­ни­чи­ва­ет­ся­ лишь первый­ аргу­мент:­

(defmethod combine ((ic ice-cream) x) (format nil "~A ice-cream with ~A."

(name ic) x))

Если­ мы теперь­ вызо­вем­ combine с экзем­п­ля­ра­ми­ ice-cream и topping, из двух послед­них­ мето­дов­ будет­ выбран­ наибо­лее­ специ­фич­ный:­

> (combine (make-instance ’ice-cream :name ’grape) (make-instance ’topping :name ’marshmallow))

"GRAPE ice-cream with MARSHMALLOW topping."

Одна­ко­ если­ второй­ аргу­мент­ не принад­ле­жит­ классу­ topping, будет­ вы­ зван только­ что опре­де­лен­­ный метод:­

> (combine (make-instance ’ice-cream :name ’clam) ’reluctance)

"CLAM ice-cream with RELUCTANCE."

Аргу­мен­ты­ обобщен­ной­ функции­ опре­де­ля­ют­ набор­ приме­ни­мых­ (app­ licable­) мето­дов­. Метод­ счита­ет­ся­ приме­ни­мым,­ если­ аргу­мен­ты­ соот­­ ветст­ву­ют­ специ­фи­ка­ци­ям,­ нала­гае­мым­ данным­ мето­дом­.

194

Глава 11. CLOS

Отсут­ст­вие­ приме­ни­мых­ мето­дов­ приво­дит­ к ошибке­. Если­ приме­ним­ лишь один метод,­ он вызы­­вает­ся­. Если­ при­мени­мо­ несколь­ко­ мето­дов,­ то в соот­вет­ст­вии­ с поряд­ком­ предше­ст­во­ва­ния­ вызы­­вает­ся­ наибо­лее­ специ­фич­ный­. Пара­мет­ры­ сверя­ют­ся­ слева­ напра­во­. Если­ первый­ па­ раметр­ одно­го­ из при­мени­мых­ мето­дов­ огра­ни­чен­ более­ специ­фич­ным­ классом,­ чем первый­ аргу­мент­ других­ мето­дов,­ то он и счита­ет­ся­ наибо­­ лее специ­фич­ным­. Ничьи­ разре­ша­ют­ся­ пере­хо­дом­ к следую­ще­му­ аргу­­ менту,­ и т. д.1

В преды­ду­щих­ приме­рах­ легко­ найти­ наибо­лее­ специ­фич­ный­ приме­­ нимый­ метод,­ так как все объек­ты­ можно­ распо­ло­жить­ по убыва­нию:­ экзем­п­ляр­ ice-cream принад­ле­жит­ классам­ ice-cream, затем­ stuff, stan­ dard-object и, нако­нец,­ t.

Мето­ды­ не обяза­ны­ исполь­зо­вать­ специ­фи­ка­то­ры,­ являю­щие­ся­ только­ класса­ми,­ опре­де­лен­­ными­ через­ defclass. Они так­же могут­ приме­нять­ типы­ (точнее­ классы,­ соот­вет­ст­вую­щие­ встроен­ным­ типам)­ . Вот при­ мер мето­да­ combine с число­вы­ми­ специ­фи­ка­то­ра­ми:­

(defmethod combine ((x number) (y number)) (+ x y))

Кроме­ того,­ мето­ды­ могут­ исполь­зо­вать­ отдель­ные­ объек­ты,­ сверяе­мые­ с помо­щью­ eql:

(defmethod combine ((x (eql ’powder)) (y (eql ’spark))) ’boom)

Специ­фи­ка­то­ры­ инди­ви­ду­аль­ных­ объек­тов­ имеют­ больший­ приори­тет,­ неже­ли­ специ­фи­ка­то­ры­ классов­.

Списки­ аргу­мен­тов­ мето­дов­ могут­ быть доволь­но­ сложны,­ как и спи­ ски аргу­мен­тов­ обычных­ функций,­ одна­ко­ они долж­ны быть конгру­­ энтны­ аргу­мен­там­ соот­вет­ст­вую­щей­ обобщен­ной­ функции­. Метод­ дол­ жен иметь столько­ же обяза­тель­ных­ и необя­за­тель­ных­ пара­мет­ров,­ сколько­ и обобщен­ная­ функция,­ и исполь­зо­вать­ либо­ &rest, либо­ &key, но не одно­вре­мен­но­. Все приве­ден­ные­ ниже­ пары­ кон­груэнт­ны:­

(x)(a)

(x &optional y) (a &optional b)

(x

y

&rest z)

(a

b

&key

c)

(x

y

&key z)

(a

b

&key

c d)

а следую­щие­ пары ­– нет:

(x)(a b)

(x &optional y) (a &optional b c) (x &optional y) (a &rest b)

(x &key x y) (a)

1Мы не сможем­ дойти­ до конца­ аргу­мен­тов­ и по-прежне­му­ иметь ничью,­ по­ тому­ что тогда­ два мето­да­ будут­ подхо­дить­ точно­ под одно­ и то же описа­ние­ аргу­мен­тов­. Это невоз­мож­но,­ так как второе­ опре­де­ле­ние­ мето­да­ в этом слу­ чае просто­ затрет­ первое­.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]