Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Cpp_Страуструп.doc
Скачиваний:
16
Добавлен:
03.05.2015
Размер:
3.2 Mб
Скачать

11.3.3.3 Шаг 3: указание зависимостей

Уточните определение классов, указав их зависимости от других классов.

Различные виды зависимостей обсуждаются в $$12.2. Основными по

отношению к проектированию следует считать отношения наследования

и использования. Оба предполагают понимание того, что значит для

класса отвечать за определенное свойство системы. Отвечать за что-либо

не означает, что класс должен содержать в себе всю информацию, или,

что его функции-члены должны сами проводить все необходимые операции.

Как раз наоборот, каждый класс, имеющий определенный уровень

ответственности, организует работу, перепоручая ее в виде

подзадач другим классам, которые имеют меньший уровень ответственности.

Но надо предостеречь, что злоупотребление этим приемом приводит

к неэффективным и плохо понимаемым проектам, поскольку

происходит размножение классов и объектов до такой степени, что

вместо реальной работы производится только серия запросов на

ее выполнение. То, что можно сделать в данном месте, следует

сделать.

Необходимость учесть отношения наследования и использования

на этапе проектирования (а не только в процессе реализации) прямо

вытекает из того, что классы представляют определенные понятия.

Отсюда также следует, что именно компонент (т.е. множество

связанных классов), а не отдельный класс, являются единицей

проектирования.

11.3.3.4 Шаг 4: определение интерфейсов

Определите интерфейсы классов. На этой стадии проектирования не нужно

рассматривать приватные функции. Вопросы реализации, возникающие на

стадии проектирования, лучше всего обсуждать на шаге 3 при

рассмотрении различных зависимостей. Более того, существует

золотое правило: если класс не допускает по крайней мере двух

существенно отличающихся реализаций, то что-то явно не в порядке с этим

классом, это просто замаскированная реализация, а не представление

абстрактного понятия. Во многих случаях для ответа на вопрос:

"Достаточно ли интерфейс класса независим от реализации?"- надо

указать, возможна ли для класса схема ленивых вычислений.

Отметим, что общие базовые классы и друзья (friend) являются

частью общего интерфейса класса (см. $$5.4.1 и $$12.4). Полезным

упражнением может быть определение раздельного интерфейса для

классов-наследников и всех остальных классов с помощью разбиения

интерфейса на общую и закрытые части.

Именно на этом шаге следует продумать и описать точные определения

типов аргументов. В идеале желательно иметь максимальное число

интерфейсов со статическими типами, относящимися к области приложения

(см. $$12.1.3 и $$12.4).

При определении интерфейсов следует обратить внимание на те

классы, где набор операций представлен более, чем на одном уровне

абстракции. Например, в классе file у некоторых функций-членов

аргументы имеют тип file_descriptor (дескриптор_файла), а у других

аргументы - строка символов, которая обозначает имя файла.

Операции с file_descriptor работают на другом уровне (меньшем)

абстракции, чем операции с именем файла, так что даже странно,

что они относятся к одному классу. Возможно, было бы лучше иметь

два класса: один представляет понятие дескриптора файла, а

другой - понятие имени файла. Обычно все операции класса должны

представлять понятия одного уровня абстракции. Если это не так,

то стоит подумать о реорганизации и его, и связанных с ним классов.