Матрёшка: второе поколение реализации шаблона «визитёр» для обхода элементов моделейВ статье Матрёшка: использование шаблона «визитёр» для обхода элементов UML модели мы уже рассматривали использование шаблона «визитёр» для обхода элементов UML модели с целью генерации кода. Поскольку с тех времён много воды утекло, да и в Матрёшке появилась совершенно иная реализация шаблона «визитёр», пришло время ещё раз обратить внимание на особенности использования новой реализации шаблона «визитёр». Новая реализация подразумевает разделение ответственности на два компонента — обработчик и обходчик. Обработчик реализуется пользователем и предназначен для выполнения полезной работы при обходе элементов; а обходчик реализует необходимый алгоритм обхода элементов. Другой важной особенностью новой реализации является возможность обработки элементов разных метамоделей в рамках одного обработчика, что часто бывает необходимым в частности для работы с моделями, использующими UML профили. Обработчик или VisitorОбработчик элементов конкретной метамодели объявляется в пакете AMF.Visitors.<Metamodel>_Visitors в виде интерфейсного типа, который содержит по две операции для каждого не абстрактного класса метамодели со следующим профилем (на примере класса Class метамодели UML): not overriding Enter_Class (Self : in out UML_Visitor; Element : not null AMF.UML.Classes.UML_Class_Access; Control : Traversal_Control) is null; not overriding Leave_Class (Self : in out UML_Visitor; Element : not null AMF.UML.Classes.UML_Class_Access; Control : Traversal_Control) is null; Приложение должно объявить собственный тэговый тип, поддерживающий любое количество интерфейсных типов обработчиков элементов и переопределить интересующие подпрограммы обработки. Обходчик или IteratorСитуация с обработчиками выглядит в некоторой степени аналогично, для каждой метамодели объявлен интерфейсный тип обходчика в пакете AMF.Visitors.<Metamodel>_Iterators. Этот интерфейсный тип имеет по одной операции для обхода элементов неабстрактных классов метамодели. Например: not overriding Visit_Class (Self : in out UML_Iterator; Visitor : in out AMF.Visitors.Abstract_Visitor'Class; Element : not null AMF.UML.Classes.UML_Class_Access; Control : Traversal_Control) is null; Приложение конечно же может определить собственный обходчик, но это зачастую не требуется, поскольку Матрёшка предоставляет компоненты для конструирования обходчика элементов на основе принципа владения. Базовый компонент объявлен в пакете AMF.Visitors.Containment, и содержит объявление интерфейсного типа и реализацию подпрограммы инициации обхода корневых элементов экстента. Этот тип может использоваться с любыми метамоделями. Для обхода элементов конкретной метамодели предоставляется настраиваемый пакет AMF.Visitors.Generic_<Metamodel>_Containment, реализующий специфический для метамодели алгоритм обхода элементов по принципу владения. Настраиваемые пакеты позволяют создавать обходчики для любого количества метамоделей путём выстраивания настроек в цепочку. Пример настройки обходчика для элементов только метамодели UML так же входит в состав Матрёшки и расположен в пакете AMF.Visitors.UML_Containment, имеющим следующее содержание: with AMF.Visitors.Containment; with AMF.Visitors.Generic_UML_Containment; package AMF.Visitors.UML_Containment is new AMF.Visitors.Generic_UML_Containment (AMF.Visitors.Containment.Containment_Iterator); Как же этим пользоватьсяНебольшой пример использования новой реализации шаблона «визитёр». Предположим, имеется некоторый генератор кода, реализованный как обработчик элементов модели со следующей спецификацией: type Generator is limited new AMF.Visitors.UML_Visitors.UML_Visitor with null record; overriding procedure Enter_Class (Self : in out Transformer; Element : not null AMF.UML.Classes.UML_Class_Access; Control : in out AMF.Visitors.Traverse_Control); Для его исполнения достаточно написать: procedure Generate (Extent : not null AMF.Extents.Extent_Access) is Iterator : AMF.Visitors.UML_Containment.UML_Containment_Iterator; Generator : Generators.Generator; begin Iterator.Visit (Generator, Extent); end; Автор: Вадим Годунко |