Взаимоотношения, о которых мы говорим, естественно устанавливаются в области приложения или (в случае повторных проходов по шагам проектирования) возникают из последующей работы над структурой классов. Они отражают наше понимание основ области приложения и часто являются классификацией основных понятий. Пример такого отношения — машина с выдвижной лестницей есть грузовик, есть пожарная машина, есть движущееся средство.
8.8.3. Шаг 2. Уточнение классов с определением набора операций (методов) для каждого
В действительности нельзя разделить процессы определения классов и выяснения того, какие операции для них нужны. Однако на практике они различаются, поскольку при определении классов внимание концентрируется на основных понятиях, не останавливаясь на программистских вопросах их реализации, тогда как при определении операций прежде всего сосредоточиваются на том, чтобы задать полный и удобный набор операций. Часто бывает слишком трудно совместить оба подхода, в особенности, учитывая, что связанные классы надо проектировать одновременно.
Возможно несколько подходов к процессу определения набора операций. Предлагаем следующую стратегию:
— рассмотрите, каким образом объект класса будет создаваться, копироваться (если нужно) и уничтожаться;
— определите минимальный набор операций, необходимый для понятия, представленного классом;
— рассмотрите операции, которые могут быть добавлены для удобства записи, и включите только несколько действительно важных;
— рассмотрите, какие операции можно считать тривиальными, т. е. такими, для которых класс выступает в роли интерфейса для реализации производного класса;
— рассмотрите, какой общности именования и функциональности можно достигнуть для всех классов компонента.
Очевидно, что это стратегия минимализма. Гораздо проще добавить любую функцию, приносящую ощутимую пользу, и сделать все операции виртуальными. Но чем больше функций, тем больше вероятность, что они не будут использоваться, наложат определенные ограничения на реализацию и затруднят эволюцию системы. Гораздо легче включить в интерфейс еще одну функцию, как только установлена потребность в ней, чем удалить ее оттуда, когда уже она стала привычной.
Причина, по которой мы требуем явного принятия решения о виртуальности данной функции, не оставляя его на стадию реализации, в том, что, объявив функцию виртуальной, существенно повлияем на использование ее класса и на взаимоотношения этого класса с другими.
При определении набора операций (методов) больше внимания следует уделять тому, что надо сделать, а не тому, как это сделать.
Иногда полезно классифицировать операции класса по тому, как они работают с внутренним состоянием объектов:
1) базовые операции: конструкторы, деструкторы, операции копирования;
2) селекторы: операции, не изменяющие состояния объекта;
3) модификаторы: операции, изменяющие состояние объекта;
4) операции преобразований, т. е. операции, порождающие объект другого типа, исходя из значения (состояния) объекта, к которому они применяются;
5) повторители: операции, которые открывают доступ к объектам класса или используют последовательность объектов.
Кроме уже перечисленных групп методов, в классы могут быть введены дополнительные методы самотестирования и проверки корректности данных. Это не есть разбиение на ортогональные группы операций. Например, повторитель может быть спроектирован как селектор или модификатор.
Выделение этих групп просто предназначено помочь в процессе проектирования интерфейса класса. Конечно, допустима и другая классификация.
8.8.4. Шаг 3. Уточнение классов с точным определением их зависимостей от других классов
Виды взаимоотношений между классами могут быть следующими: отношения наследования; отношения включения; отношения использования; запрограммированные отношения.
Еще одно взаимоотношение — отношение включения {агрегирования) — класс содержит в виде члена объект или указатель на объект другого класса. Позволяя объектам содержать указатели на другие объекты, можно создавать так называемые "иерархии объектов". Такие реализации альтернативно дополняют возможности использования иерархии классов.
Очень важным при проектировании является вопрос: какое отношение выбрать — агрегации (включения) или наследования. В принципе эти методы взаимозаменяемы, кроме случая, когда используется позднее связывание. Наиболее предпочтителен тот вариант, в котором наиболее точно моделируется окружающая действительность, т. е. если понятие X является частью понятия Y, то используется включение. Если понятие X более общее, чем Y, — то наследование.
Читать дальше