Предмет данной статьи - инспектор объектов как средство, доступное конечному пользователю некоторой прикладной программы. Само понятие "инспектор" трактуется в данном случае очень широко: инспектор - это инструмент прикладной программы, с помощью которого пользователь может посмотреть и изменить свойства тех объектов, с которыми он работает. Отметим, что речь идет о любых объектах прикладного уровня, а не только о визуальных компонентах (как в Delphi).
Мотивация и постановка задачи
При попытке сформулировать требования к инспектору объектов у меня получился такой список :
инспектор должен иметь возможность работать с объектами любых типов. Не предполагается происхождение объектов от какого-либо специального базового класса, |
|
должна существовать возможность инспектирования объектов, которые были созданы на предыдущих этапах разработки. Это случай, когда инспектор появляется в прикладной программе в результате ее эволюционного развития при длительном времени жизни программы. Инспектируемые объекты могут иметь различную природу, например, вообще быть не объектами, а, например, структурами данных (записями), располагаться в адресном пространстве другого процесса, или находиться на удаленной машине в локальной сети. Инспектор должен однообразно работать с объектами различной природы, |
инспектируемые объекты могут выглядеть по-разному для разных пользователей или разных контекстов и могут предоставлять для инспекции различные наборы своих свойств. Например, с прикладной программой могут работать пользователи различных категорий: "новичок", "обычный пользователь", "эксперт". Естественно, что "эксперту" доступно большее число инспектируемых свойств, чем "новичку", |
|
объекты могут иметь сложную внутреннюю структуру, то есть, содержать вложенные объекты, которые, в свою очередь, также могут иметь вложенные объекты. Вложенность объектов неограничена (в разумных пределах), |
число инспектируемых свойств может быть достаточно большим, при этом должны существовать средства иерархической упорядоченности, то есть, свойства могут быть представлены, в общем случае, как элементы дерева, веточки которого можно сворачивать и разворачивать, |
|
инспектор должен сохранять историю работы с различными объектами, то есть, при повторе инспекции объекта, внешний вид дерева его свойств должен быть таким же, как и при последней инспекции. Это означает, что инспектор должен сохранять историю сворачивания и разворачивания веточек, |
имена свойств могут быть на любом языке, например, на русском, и могут включать произвольный набор символов. Имена могут иметь достаточно большую длину и составляться из нескольких слов, |
|
должна существовать развитая система помощи, включающая, как минимум, два уровня по каждому инспектируемому свойству - подсказка и справка, |
реализация всех этих условий не должна быть связана с большими трудозатратами со стороны программиста. |
Может показаться, что это завышенный набор требований, но, тем не менее, все перечисленные пункты были не придуманы, а продиктованы той реальной необходимостью, которую мне пришлось учитывать в одном из выполняемых мною проектов.
Как видно из перечисленных выше требований, объекты должны обладать существенно большим набором аттрибутов, чем это требуется нам, программистам, для работы с объектами внутри программного кода. Для обозначения этой дополнительной информации будем использовать термин "метаданные" или "аттрибуты". Приставка "мета" подчеркивает, что это данные, описывающие другие данные, то есть, "данные о данных". Именно такие термины используются в языке C# и в платформе .Net. Примером метаданных является информация RTTI, которую формирует компилятор Delphi. Очевидно также, что метаданные, формируемые Delphi недостаточны для удовлетворения всех поставленных требований, а такая возможность, как описание своих аттрибутов (доступная в C#), в Delphi отсутствует. Кроме того, нужно удовлетворить указанному выше требованию о том, что инспектор должен работать и с такими объектами, которые не были спроектированы в расчете на инспекцию.
При анализе поставленных требований я выделил четыре основные задачи, необходимые для создания инспектора. Каждой из этих задач посвящен в статье свой раздел:
создание метаданных, размещение метаданных и доступ к ним, |
|
создание прокси-объектов (заместителей), работающих с объектами различной природы и унифицирующих способ взаимодействия объектов с инспектором, |
создание менеджера объектов, который изолирует визуальный компонент инспектора от инспектируемых объектов и метаданных, |
|
создание собственно инспектора как визуального компонента. |
Метаданные
Можно придумать, вероятно, много различных способов организации метаданных. Например, метаданные объектов различных типов можно описывать в отдельном файле (или файлах) в каком-либо формате, например, как текст на языке XML. Структура метаданных может быть в этом случае сколь угодно сложной и содержать такие крупные разделы, как категория пользователя или локализация. Файлы метаданных можно распространять вместе с программой или внести их в ресурсы, размещаемые в самой программе или в DLL. Для доступа к метаданным потребуется некоторого рода база или список метаданных, индексируемых именем типа, а также XML-парсер для разбора текста.
Я остановил свой выбор на таком способе - хранение метаданных в виде статических классов, регистрируемых в реестре метаданных. Статическими классами будем называть классы, которые содержат только классовые методы и ничего больше. Особенностью таких классов является то, что с ними можно работать без динамического инстанцирования экземляров во время выполнения. Метаданные вводятся как локальные константные записи, доступ к которым выполняется с помощью классовых методов. Все классы метаданных порождаются от базового статического класса TGsvObjectInspectorTypeInfo, виртуальные классовые методы которого переопределяются в классах метаданных. Определение TGsvObjectInspectorTypeInfo выглядит так:
Code: |
TGsvObjectInspectorTypeInfo = class public classfunction ObjectName(AObject: TObject): String; virtual; classfunction TypeName: String; virtual; classfunction TypeInfo: PGsvObjectInspectorPropertyInfo; virtual; classfunction ChildrenInfo(Index: Integer): PGsvObjectInspectorPropertyInfo; virtual; classprocedure FillList(AObject: TObject; List: TStrings); virtual; classprocedure ShowDialog(Inspector: TComponent; Info: PGsvObjectInspectorPropertyInfo; const EditRect: TRect); virtual; classfunction IntegerToString(const Value: LongInt): String; virtual; classfunction StringToInteger(const Value: String): LongInt; virtual; classfunction CharToString(const Value: Char): String; virtual; classfunction StringToChar(const Value: String): Char; virtual; classfunction FloatToString(const Value: Extended): String; virtual; classfunction StringToFloat(const Value: String): Extended; virtual; classfunction ObjectToString(const Value: TObject): String; virtual; end; |
- Назад
- Вперёд >>
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!