понедельник, 25 июня 2012 г.

Об Архитектуре

Сегодня я хотел бы начать разговор об архитектурных паттернах и о том, каким образом они могут оказаться полезны в жизни. Я не буду ничего говорить о паттернах GoF  (которые, безусловно, нужны и полезны всем тем, кто вслед за Бандой разрабатывает “визуальные редакторы документов, построенные по принципу WYSIWYG  и аналогичные приложения”), а сосредоточусь на не менее интересных (но возможно несколько менее известных) документах TM Forum (а именно SID), позволяющих описать предметную область приложений, работающих в сфере телекоммуникаций.

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

Сущность



Исходя из SID-а, Сущность (Entity) представляет собой абстрактный класс, наследуемый от RootEntity, предоставляющий get-еры и set-еры к нескольким атрибутам, а также сохраняющий строковое значение версии. С RootEntity связаны следующие атрибуты:


Атрибут
Назначение
commonName
Обязательный атрибут сохраняющий “дружественное” описание объекта, составленное в соответствии с принятыми в разрабатываемой системе правилами именования объектов и используемое, например, при отображении объекта в GUI
description
Необязательный атрибут, описывающий, в свободной форме, назначение объекта
objectID
Обязательный атрибут, содержащий уникальный идентификатор объекта, используемый приложением во внутренних целях



Все это хорошо, но душа жаждет большего (например, использования при проектировании интерфейсов (почему при разработке приложений стоит использовать интерфейсы и когда их использовать не стоит – темы для отдельных обширных дискуссий). Поскольку SID не догма, а руководство к действию видоизменим диаграмму, добавив в нее интерфейсы и некоторую дополнительную функциональность:




Помимо интерфейсов (необходимость применения которых вполне обсуждаема), мы добавили (на уровне Entity) возможность хранения неких именованных значений (атрибутов). Пока что, для простоты изложения, будем считать, что эти значения строковые, но, строго говоря, ни строковыми, ни даже скалярными они быть совсем не обязаны.

Хочу специально обратить внимание, что IEntity не наследует IRootEntity. Поскольку аналогичное наследование есть на уровне абстрактных классов, наследование интерфейсов не даст нам ничего принципиально нового, но помешает создавать объекты хранящие списки именованных значений, но не имеющие идентификаторов.

Итак, наша сущность умеет хранить уникальный идентификатор и список именованных значений. Но как нам узнать какие именно именованные значения хранит Сущность? В этом нам поможет Спецификация.


Спецификация



 
Согласно SID-у абстрактный класс Specification наследуется от RootEntity (то есть имеет имя и уникальный идентификатор) и является родителем EntitySpecification (дополнительный уровень наследования введен, поскольку специфицировать может понадобиться не только сущности). С EntitySpecification может быть ассоциировано 0 и более Entity.


Абстрактный класс Specification определяет следующие атрибуты:
Атрибут
Назначение
specValidFor
Период действия спецификации
specLifeCycleStatus
Текущий статус спецификации (в рамках ее жизненного цикла)
specVersion
Версия спецификации
 
Согласно тому-же SID-у, спецификация предназначена для описания инвариантных характеристик Entity (таких как атрибуты, методы, ограничения и связи). Реализация этого хранения полностью отдана на откуп разработчику, чем мы немедленно и воспользуемся.


Поскольку SID никак не регламентирует функциональность EntitySpecification, у нас полностью развязаны руки при определении ее интерфейса. Приведенное определение IEntitySpecification ни в коем случае не должно рассматриваться как что-то стандартное, но, на мой взгляд, предоставляет необходимый минимум методов для спецификации сущностей, хранимые атрибуты которых ограничены строковым типом. Рассмотрим эти методы подробнее:


Метод
Назначение
getTypeName
Этот метод, у нас, будет возвращать строковый objectID из RootEntity, который мы будем называть типом сущности. Как будет показано далее, для типов сущностей имеет смысл определять иерархию.
Так, например, тип ‘ri может быть ассоциирован с корневой спецификацией, описывающей объекты Resource Inventory, а ‘ri.device’ ее дочерней спецификацией, описывающей устройства.
Можно пойти еще дальше и определить, например, спецификацию ‘ri.device.valid’ описывающую исправные устройства (мы вернемся к этому моменту, когда будем рассматривать взаимосвязь Specification и Policy)
getParentSpecification
Используя этот метод, мы всегда сможет получить родительскую спецификацию. При вызове этого метода у корневой спецификации, можно бросать исключение
getAttributeNames
Этот метод будет возвращать коллекцию имен атрибутов сохраняемых описываемой сущностью
isMandatoryAttribute
Зная имя атрибута, и используя этот метод, мы можем проверить, является ли атрибут обязательным. Ситуация кода Entity не сохраняет значение для обязательного атрибута должна рассматриваться как ошибка
isConstantAttribute
Этот метод показывает, разрешено ли изменение значения для данного атрибута. Константные атрибуты будут использоваться нами далее для идентификации сущностей
getDefaultValue
Используя этот метод, можно получить значение по умолчанию, которое следует использовать, если сущность не сохраняет значение для данного атрибута


Описанный выше интерфейс позволяет единообразно хранить описание сущностей (и соответственно работать с сущностями зная имена и типы их атрибутов). Несколько менее очевидно то, что одна и та же сущность может рассматриваться, фактически, как совершенно различные сущности (содержащие различные наборы значений). О том, зачем это может понадобиться, мы будем говорить, когда речь зайдет об архитектуре приложения. В настоящий момент нас более должен занимать другой вопрос. Как имея экземпляр Entity получить спецификацию, которая ее описывает? Решением этого вопроса и занимается идентификация, которую мы рассмотрим далее.


Идентификация




Попробуем прочитать эту загадочную картинку. Итак, с сущностью Entity связано некоторое количество EntityIdentification, содержащих значения, совокупность которых уникально идентифицирует экземпляр сущности. С другой стороны, EntityIdentificationSpecification ассоциирует наборы этих значений со спецификациями EntitySpecification. Для EntityIdentificationSpecification определены следующие атрибуты:
Атрибут
Назначение
name
Имя EntityIdentificationSpecification (как экземпляра RootEntity)
description
Описание, понятное человеку
validFor
Период действия
  
Какова главная цель использования EntityIdentificationSpecification? По всей видимости, он должен помочь нам, имея экземпляр сущности и некоторые априорные знания о ее типе (например, спецификацию родительского типа) получить точную спецификацию сущности. Определим это явно в форме интерфейса:
Зная имя родительской спецификации (например ‘ri’) и используя экземпляр, реализующий IEntity, мы получаем экземпляр спецификации (например, имеющий тип ‘ri.device’), наиболее полно описывающий сущность.
Как мы можем этого добиться? В этом нам сильно помогут константные атрибуты (фактически описывающие значения EntityIdentification). Действительно, мы можем определить правило проверки константного атрибута (например ‘TYPE_ID’), которое будет заключаться в том, что если значение TYPE_ID = 1 для экземпляра сущности Resource Inventory, то этот экземпляр следует рассматривать как устройство (‘ri.device’).
Другой важной задачей идентификации является валидация экземпляра сущности. Спецификация не возвращается до тех пор, пока EntityIdentificationSpecification не проверит корректность заполнения атрибутов (например, наличие всех обязательных полей и корректность константных значений атрибутов). В случае если экземпляр сущности не валиден, EntityIdentificationSpecification бросит исключение.
По завершении идентификации, мы можем связать сущность с полученной спецификацией:
 
Являясь наследником IEntity, SpecifiedEntity позволит работать лишь с теми значениями, имена атрибутов которых описаны в спецификации, а также подставит значения по умолчанию для отсутствующих не обязательных значений.

Комментариев нет:

Отправить комментарий