Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 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 работают на другом уровне (меньшем) абстракции, чем операции с именем файла, так что даже странно, что они относятся к одному классу. Возможно, было бы лучше иметь два класса: один представляет понятие дескриптора файла, а другой - понятие имени файла. Обычно все операции класса должны представлять понятия одного уровня абстракции. Если это не так, то стоит подумать о реорганизации и его, и связанных с ним классов.