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