Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++ (1158635), страница 56
Текст из файла (страница 56)
С этим шагом связано три вида деятельности:спецификация ассоциаций, идентификация различных взаимодействий иуточнение ассоциаций. Спецификация ассоциаций является одним изосновных действий в анализе и на ранней стадии проектирования. Какобъяснялось в главе 3, ассоциации семантически слабы: они обозначаюттолько некоторую семантическую зависимость, роль каждого участника связии кардинальность связи и, возможно, направление допустимого перехода.Однако для анализа и ранней стадии проектирования этого часто достаточно,ибо передаются все важные детали связей между двумя абстракциями, приэтом предохраняя нас от поспешных решений о реализации.
Типичныйпорядок выполнения данного этапа таков:•Выбрать множество классов данного уровня абстракции илиассоциированных с некоторым набором сценариев; нанести надиаграммы все важнейшие операции и атрибуты, необходимые дляиллюстрации существенных свойств моделируемой задачи.•Выяснить наличие зависимости между каждыми двумя классами иустановить ассоциацию, если она присутствует. Необходимостьперехода от одного объекта к другому и неизбежностьиспользования некоторого поведения другого объекта являютсяпричиной введения ассоциации.
Чтобы устранить косвенныезависимости, следует ввести новые абстракции, которые служилибы агентами или посредниками. Некоторые ассоциации могут бытьсразу идентифицированы как отношение "частное/общее" илиагрегации.•Для каждой ассоциации определить роль каждого участника, еслинеобходимо уточнить кардинальность и выявить другиеограничения.•Проверить годность этих решений, для чего просмотреть сценарий иубедиться, что имеющиеся ассоциации необходимы и достаточныдля получения требуемых переходов и поведения абстракций этогосценария.Диаграммы классов - основные модели, получаемые на данном этапе.Идентификация взаимодействий происходит главным образом припроектировании и, как описано в главе 4, является задачей классификации.
А,значит, она также требует творчества и интуиции. В зависимости от текущегосостояния макропроцесса, мы должны рассмотреть несколько различныхтипов взаимодействия:•Как часть формулировки наших стратегических решений, мы должнысоставить для каждого определенного на предыдущем шагемеханизма диаграмму объектов, иллюстрирующую егодинамическую семантику. Проверить каждый механизм вцентральных и периферийных сценариях.
Где возможенпараллелизм, назначить объекты - актеры, агенты и серверы испособы синхронизации между ними. При этом можетпонадобиться ввести новые связи между объектами и устранитьнеиспользованные или избыточные.•Если между классами наблюдается общность, необходимо поместитьэти классы в иерархию "общее/частное". Как говорилось в главе 3,обычно лучше создать "лес" классов, чем единое дерево. Напредыдущем шаге мы уже определили кандидатов на базовые,абстрактные классы и классы-примеси; теперь нужно разместитьих в структуре наследования. Для существенных классов следуетрассмотреть диаграммы классов и оценить их качество, согласноэвристикам главы 3.
В частности, требует особого вниманияиерархическая структура: она не должна быть слишком высокойили слишком короткой, чересчур широкой или узкой. Там, гдевстречаются шаблоны в структуре или поведении, нужнореорганизовать иерархию так, чтобы максимизировать общность(но не в ущерб простоте).•Как часть архитектурного проектирования, мы должны рассмотретьгруппирование классов в категории и организацию модулей вподсистемы. Это - стратегические решения. Архитекторы могутиспользовать диаграммы классов, чтобы определить иерархиюкатегорий классов, которая формирует слои и разделыразрабатываемой системы. Обычно это делается сверху вниз. Имеяглобальное представление о системе, выделяют основныеабстракции, выполняющие главные обязанности системы, которыеявляются логически связными и могут изменяться независимо.Архитектуру также можно модернизировать снизу вверх, когдапри каждом прохождении через микропроцесс идентифицируютсясемантически замкнутые группы классов.
Нужно также принятьрешения о распределении классов по категориям. Еслисуществующие категории слишком раздуваются илиобнаруживаются новые группы классов, можно ввести новыекатегории или реорганизовать старые. Выявление модулей (дляфизической модели системы) выполняется аналогично и принятыерешения отражаются на диаграммах модулей.•Распределение классов и объектов по модулям является до некоторойстепени локальным решением и чаще всего отражает отношениявидимости абстракций. Как мы указывали в главе 5, отображениелогической модели в физическую дает возможность разработчикуоткрыть или ограничить доступ к каждой абстракции илиупаковать вместе логически связанные абстракции, которыепредполагается изменять по отдельности.
Как мы обсудим вследующей главе, на отображение логической модели вфизическую влияет также распределение обязанностей в командепроектировщиков. В любом случае все принятые решения можновыразить в виде диаграммы модулей.Третий вид деятельности в этой фазе микропроцесса - уточнениеассоциа-ций - относится и к анализу, и к проектированию. При анализе мыможем провести вместо некоторых ассоциаций другие, семантически болееточные связи, что-бы отразить наши достижения в понимании прикладнойобласти.
Таким образом, преобразовывая ассоциации и добавляя новыеконкретные связи, мы готовим на-бросок реализации.Отношения наследования, агрегации, инстанцирования ииспользования - важнейшие типы ассоциаций, представляющие для насинтерес вместе с такими свойствами, как метки, роли, кардинальность и т.
д.Типичный порядок уточнения ассоциаций таков:•Имея набор классов, уже разбитый на группы, следует найтишаблоны поведения, указывающие на возможную связь"общее/частное". Далее необходимо разместить эти классы всуществующей структуре наследования или построить новуюподходящую структуру.•Если имеются шаблоны структуры, то, используя наследование склассами-примесями или агрегацию, попробовать ввести новыеклассы, отражающие общность структуры.•Найти классы с похожим поведением, которые либо находятся наодном уровне, либо еще не входят в структуру наследования ирассмотреть возможность введения общих параметризованныхклассов.•Рассмотреть существующие ассоциации с точки зрения переходовмежду ними и ограничить их насколько возможно.
Если нетребуется двустороннего перехода, считать связь простымотношением использования.•Определить тактические детали: указать роли, ключи,кардинальность, дружественность и т. д. Не требуется излишнедетализировать: достаточно включить лишь важные результатыанализа и проектирования или то, что необходимо для реализации.Путевые вехи и характеристики. Мы благополучно завершим этуфазу, когда достаточно полно определим семантику и связи интересующихабстракций, чтобы приступить к началу реализации.Меры качества - связность, зацепление и полнота.
Пересматриваясвязи, которые мы обнаружили или изобрели в течение этой фазы, мы хотимполучить связные и слабо зацепленные между собой абстракции. При этом мыдолжны идентифицировать все важные связи на данном уровне абстракции,чтобы реализация не требовала введения новых существенных связей илинеестественного использования тех, которые мы уже определили.
Если наследующем шаге обнаружится, что наши абстракции неудобны дляреализации, то это будет признаком того, что мы еще не определилиподходящего набора связей между ними.Реализация классов и объектовЦель. На этапе анализа реализация классов и объектов нужна, чтобыдовести существующие абстракции до уровня, достаточного для обнаруженияновых классов и объектов на следующем уровне абстракции; они сами будут вдальнейшем поданы на новую итерацию микропроцесса. При проектированиицелью реализации становится создание осязаемого представления нашихабстракций путем выпуска последовательных исполнимых версий системы(макропроцесс).Этот шаг намеренно выполняется позже всех, так как микропроцессконцентрирует внимание на поведении и откладывает насколько возможнорешения о представлении.
Такая стратегия оберегает разработчика отнедозрелых решений, которые могут не оставить шансов на облегчение иупрощение архитектуры, и оставляет свободу выбора реализации (например,из соображений эффективности), гарантируя сохранение существующейархитектуры.Результаты. На этом шаге мы принимаем решения о представлениикаждой абстракции и об отображении этих абстракций в физическую модель.В начале процесса разработки мы формулируем эти тактические решения опредставлении в форме уточненных спецификаций классов.
Решения,имеющие общий интерес, или подходящие для повторного использования, мыдокументируем также на диаграммах классов (показывающих их статическуюсемантику), состояний и взаимодействия (показывающих их динамическуюсемантику). Когда становится ясно, на каком языке реализовывать проект,можно начинать программировать в псевдокоде или в исполнимом коде.Чтобы раскрыть связи между логическим и физическим в нашейреализации системы, мы вводим диаграммы модулей, которые можно затемиспользовать, чтобы наглядно показать отображение нашей архитектуры в еепрограммную реализацию.
Далее можно применить специфическиеинструментальные средства, которые позволяют либо генерировать код издиаграмм, либо восстанавливать диаграммы по реализации.В этот шаг входит и обновление словаря данных, включая новыеклассы и объекты, которые были выявлены или изобретены при реализациисуществующих абстракций. Эти новые абстракции являются частью исходнойинформации для следующего цикла микропроцесса.Виды деятельности. С реализацией связано одно главное действие:выбор структур и алгоритмов, которые представляют семантикуопределенных ранее микропроцессом абстракций. В отличие от первых трехстадий микропроцесса, сосредоточенных на внешних представленияхабстракций, этот этап акцентирует внимание на их внутреннем представлении.На стадии анализа результаты этого действия относительноабстрактны: мы не так обеспокоены собственно реализацией, какзаинтересованы в отыскании новых абстракций, которым можно делегироватьобязанности.
На стадии проектирования, особенно на поздних стадияхпроектирования классов, мы действительно переходим к практическимрешениям.Типичный порядок действий таков:•Пересмотреть протокол каждого класса. Идентифицироватьстереотипы его использования объектами-клиентами, чтобыопределить, какие операции являются центральными и,следовательно, должны быть оптимизированы. Для облегченияреализации разработать точные сигнатуры всех важнейшихопераций.•Рассмотреть возможность использования параметризованныхклассов, закрытого или защищенного наследования в реализации.Выбрать подходящие классы-примеси или параметризованныеклассы (или создать новые, если задача достаточно общая) исоответствующим образом изменить структуру наследования.•Рассмотреть объекты, которым можно делегировать обязанности.