Бьерн Страуструп. Язык программирования С++


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



бет97/124
Дата16.07.2016
өлшемі3.27 Mb.
#204081
түріКнига
1   ...   93   94   95   96   97   98   99   100   ...   124

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 работают на другом уровне (меньшем)

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

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

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

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

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

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



11.3.3.5 Перестройка иерархии классов


Шаги 1 и 3 требуют исследования классов и их иерархии, чтобы

убедиться, что они адекватно отвечают нашим требованиям. Обычно

это не так, и приходится проводить перестройку для улучшения

структуры, проекта или реализации.

Самая типичная перестройка иерархии классов состоит в выделении

общей части двух классов в новый класс или в разбиении класса на два

новых. В обоих случаях в результате получится три класса:

базовый класс и два

производных. Когда следует проводить такую перестройку? Каковы

общие показания, что такая перестройка будет полезной?

К сожалению нет простого и универсального ответа на эти

вопросы. Это и не удивительно, поскольку то, что предлагается,

не является мелочью при реализации, а изменяет основные

понятия системы. Важной и нетривиальной задачей является поиск

общности среди классов и выделение общей части. Нет точного

определения общности, но следует обращать внимание на общность

для понятий системы, а не просто для удобства реализации. Указаниями,

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

класс, служат схожие способы использования, сходство наборов операций,

сходство реализаций и просто тот факт, что часто в процессе обсуждения

проекта оба класса появляются одновременно. С другой

стороны, если есть

несколько наборов операций класса с различными способами использования,

если эти наборы обеспечивают доступ к раздельным подмножествам объектов

реализации, и, если класс возникает в процессе обсуждения несвязанных

тем, то этот класс является явным кандидатом для разбиения на части.

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

перестройки иерархии классов высвечиваются на поверхности проблем

именования классов и использования имен классов в процессе обсуждения

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

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

видимости, есть возможность улучшения иерархии. Заметим, что

подразумевается, что анализ иерархии классов лучше проводить не в

одиночку. Если вы оказались в таком положении, когда не с кем

обсудить проект, хорошим выходом будет попытаться составить учебное

описание системы, используя имена классов.



Достарыңызбен бөлісу:
1   ...   93   94   95   96   97   98   99   100   ...   124




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет