Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 174
Текст из файла (страница 174)
Итак, рассмотрим, как можно подойти к проектированию компоненты. Поскольку зачастую это непростая задача, с~опт разбить ее на этапы, чтобы логичным образом сфокусироваться на разных подзадачах. Как обычно, для мого пет универсального правильного способа. Однако, вот последовательность действий, которая кое-кому помогла: 11] Выявите понятия7классы и их самые фундаментальные взаимосвязи. 12] Уточните классы, определив набор операций над ними. Классифицируйте эти операции, В частности, рассмотрите потребность в конструкторах, деструкторах и копировании.
° Рассмотрите минималыюсть, полноту и удобство. 13] Уточните классы, определив их взаимозависимость. Рассмотрите параметризацию, наследование и воспользуйтесь зависимостью. 14] Определите интерфейсы. Разделите функции на открьпые и защищенные. Определите точный тип операций над классом. 772 Глава 23. Разработка и проектирование Отметим, что это этапы итеративного процесса. Как правило, чтобы получгпь проект, которым удобно пользоваться при первоначальной или повторной реализации, требуется несколько проходов по указанному циклу.
Одно из преимуществ хорошо выполненных анализа и абстракции данных заключается атом, что становится относительно просто перетасовывать классы даже после того, как программа написана. Впрочем, это всегда нетривиальная задача. После этого мы реализуем классы, возвращаемся назад и пересматриваем проект, уже обогащенные опытом его реализации. В следующих подразделах я обсуждаю эти этапы один за другим. 23.4.3.1. Этап 1: выявление классов Выявляем понятия/классы и их салгые фундамеггтальные взаимосвязи. Ключ к хорошему проекту — смоделировать некоторый аспект «реальности» напрямую, то есть понять концепции программы как классы, представить отношения между ними четко определенным способом, таким как наследование, и повторить это многократно на разных уровнях абстракции. Но как нам найти эти концепции7 Как на практике решить, какие классы пам нужны? Лучше всего начать поиски с самого приложения, а не рыться в портфеле с абстракциями н концепциями компьютерного ученого.
Послугпайте того, кто собирается стать профессиональным пользователем системы, когда опа будет реализована, ггли того пользователя, который неудовлетворен существуклцей системой, подлежащей замене. Обратите внимание па термины, которыми опи пользуются. Часто говорят (и часто это действительно так), что классам и объектам в программе будут соответствовать существительные. Однако, это ни в коем случае еще не конец. Глаголы могут подсказать операции над объектами, традиционные (глобальные) функции, которые предоставляю~ новые значения, основываясь на аргументах, или даже классы. Как пример последнего, отметим объекты-функции Я 1ЯА) и манипуляторы (г) 21А.6).
Такие слова как «несколько раз проходить» или «выполнять» можно представить соответственно объектами-итераторамп и объектами, представляющими транзакции в базе данных. Часто с пользой для дела классами можно представггть ггаже прилагательные. Рассмотрим прилагательные «хранящиеся», «одновременггые», «зарепгстрнрованные» и «ограниченные». Они могут стать классамп, позволяющими проектировщику или программисту выбрать подходящие атрибуты классов, которые будут спроектированы в будущем, путем указания соответствующих виртуальных базовых классов (ф 15.2.4).
Не все классы соотносятся с понятиями на уровне программы. Например, некоторые классы представляют ресурсы системы и абстракции на уровне реализации Я 24.3.1). Также важно избегать слишком похожего моделирования старой системы. Например, мы пе хотим, чтобы система управления базами данных точно воспроизводила все аспекты старой системы, существующей только для того, чтобы помогать людям управляться с перекладыванием бумаг «вручную», Наследование используется для того, чтобы выразить общность понятий.
Очень важно, чтобы оно использовалось для отражения иерархической организации, основывающейся на поведении классов, представляющих отдельные понятия Я 1.7, ч 12.2.6, г) 24.3.2). Иногда это называют классификациейг или даже таксогголгивй 23.4. Процесс разработки 773 Нужно активно искать общность. Универсализация и классификация — это деятельность верхнего уровня, требующая проникновения в сущность системы, чтобы дать полезные, а не сиюминутные результаты. Общая база должна представлять собой более глубокую, а не просто схожую концепцию, которая требует для своего представления меныпе данных. Отметим, что классифицировать нужно те аспекты концепций, которые мы моделируем в нашей системе, а не те, которые могут иметь смысл в других областях.
Например, в математике окружность — это частный случай эллипса, но в большинстве программ окружность не нужно выводить из эллипса, или делать эллипс потомком окружности. Часто приводимые аргументы «потому что так в математике» или «потому что окружность является частным случаем эллипса» неубедительны или даже ошибочны. Дело в том, что для многих программ ключевое свойство окружности — равноудаленность се центра от всех точек периметра.
Это свойство должно поддерживаться всем поведением (всеми операциями) окружности (то есть это свойство является инвариантом, 9 243.7.1). В свою очередь эллипс характеризуется двумя точками фокуса, которые во многих программах могут независимо друг от друга изменяться. Если этн точки фокуса совмещаются, эллипс с~ввозится похож на окружность, но это не окружность, поскольку его операции не сохраняют инварианта окружности. В большинстве систем это различие будет отражено разным набором операций для аллипса и окружности, и один набор не будет являться подмножеством другого.
Мы не просто придумываем набор классов и отношений между классами и используем его в окончательной системе. Нет, мы создаем первоначальный набор классов и их взаимоотношений, а затем многократно совершенствуем его (9 23.4.3.5), чтобы получить набор классов достаточно универсальный, гибкий и стабильный для оказания по- моши в дальнейшей эволюции системы Лучшим инструментом для выявления первоначальных понятий/классов является классная доска. Лучший способ для их усовершенствования,— обсуждение со специалистами в области применения и несколькими друзьями.
Обсуждения необходимы для развития жиансспособного словаря и базовой системы понятий. Не многие могут сделать это в одиночку. Одним из способов развить набор полезных классов из первоначального набора кандидатов является моделирование системы, где роль классов играют проектировщики. Это может выявить абсурдность первоначальных идей, стимулировать споры об альтернативах и создать общее понимание развивающегося проекта. Эта деятельность может поддерживаться и документироваться заметками на каталожных карточках.
Такие карточки, в соответствии с информацией, которую на них записывают, обычно называют СКС-карточками («С!азз, Везропз1Ь1!!гу, апд Со!!аЬогагогз», «класс, ответственность, сотрудники» (%"!г(з-Вгос!г, 1990]). Пример использовипия — это описание частного использования системы. Вот простой пример использования телефонной системы; берем трубку, набираем номер, на другом конце звони~ телефон, там снимают трубку. Выявление таких типичных случаев использования может оказаться очень ценным на всех стадиях разработки. Сначала описание случаев использования поможет нам понять, что мы собираемся построить.
В процессе проектирования их можно использовать (например, при помощи СКС-карточек), чтобы проверить, что относительно постоянное описание системы в терминах классов и объекчов действительно имеет смысл с точки зрения пользователя. Во время программирования и тестирования примеры исполь- 7?4 Глава 23. Разработка и проектирование зования становятся источником тестов. Таким образом примеры использования обеспечивают ортогональный взгляд на систему и служат проверкой соответствия с реальностью. Примеры использования описывают систему как 1динамическую) работающую сущность. Поэтому они могут соблазнить проектировщика функциональным анализом системы и отвлечь от важной задачи по поиску полезных концепций, которые можно отобразить в классах.