straustrup2 (852740), страница 77
Текст из файла (страница 77)
$$12.2.3)Отметим, что стратегия минимализма требует, пожалуй, больших усилий со стороны разработчика.При определении набора операций больше внимания следует уделять тому, что надо сделать, а нетому, как это делать.Иногда полезно классифицировать операции класса по тому, как они работают с внутреннимсостоянием объектов:-Базовые операции: конструкторы, деструкторы, операции копирования.-Селекторы: операции, не изменяющие состояния объекта.-Модификаторы: операции, изменяющие состояние объекта.-Операции преобразований, т.е. операции порождающие объект другого типа, исходя иззначения (состояния) объекта, к которому они применяются.-Повторители: операции, которые открывают доступ к объектам класса или используютпоследовательность объектов.Это не есть разбиение на ортогональные группы операций.
Например, повторитель может бытьспроектирован как селектор или модификатор. Выделение этих групп просто предназначено помочь впроцессе проектирования интерфейса класса. Конечно, допустима и другая классификация.Проведение такой классификации особенно полезно для поддержания непротиворечивости междуклассами в рамках одного компонента.В языке С++ есть конструкция, помогающая заданию селекторов и модификаторов в виде функциичлена со спецификацией const и без нее.
Кроме того, есть средства, позволяющие явно задатьконструкторы, деструкторы и функции преобразования. Операция копирования реализуется с помощьюопераций присваивания и конструкторов копирования.11.3.3.3 Шаг 3: указание зависимостейУточните определение классов, указав их зависимости от других классов.
Различные видызависимостей обсуждаются в $$12.2. Основными по отношению к проектированию следует считатьотношения наследования и использования. Оба предполагают понимание того, что значит для классаотвечать за определенное свойство системы. Отвечать за что-либо не означает, что класс долженсодержать в себе всю информацию, или, что его функции-члены должны сами проводить всенеобходимые операции. Как раз наоборот, каждый класс, имеющий определенный уровеньответственности, организует работу, перепоручая ее в виде подзадач другим классам, которые имеютменьший уровень ответственности. Но надо предостеречь, что злоупотребление этим приемомприводит к неэффективным и плохо понимаемым проектам, поскольку происходит размножениеклассов и объектов до такой степени, что вместо реальной работы производится только серия запросовна ее выполнение.
То, что можно сделать в данном месте, следует сделать.Необходимость учесть отношения наследования и использования на этапе проектирования (а не тольков процессе реализации) прямо вытекает из того, что классы представляют определенные понятия.Отсюда также следует, что именно компонент (т.е.
множество связанных классов), а не отдельныйкласс, являются единицей проектирования.11.3.3.4 Шаг 4: определение интерфейсовОпределите интерфейсы классов. На этой стадии проектирования не нужно рассматривать приватныефункции. Вопросы реализации, возникающие на стадии проектирования, лучше всего обсуждать нашаге 3 при рассмотрении различных зависимостей.
Более того, существует золотое правило: есликласс не допускает по крайней мере двух существенно отличающихся реализаций, то что-то явно не в294Бьерн Страуструп.Язык программирования С++порядке с этим классом, это просто замаскированная реализация, а не представление абстрактногопонятия. Во многих случаях для ответа на вопрос: "Достаточно ли интерфейс класса независим отреализации?"- надо указать, возможна ли для класса схема ленивых вычислений.Отметим, что общие базовые классы и друзья (friend) являются частью общего интерфейса класса (см.$$5.4.1 и $$12.4). Полезным упражнением может быть определение раздельного интерфейса дляклассов-наследников и всех остальных классов с помощью разбиения интерфейса на общую изакрытые части.Именно на этом шаге следует продумать и описать точные определения типов аргументов.
В идеалежелательно иметь максимальное число интерфейсов со статическими типами, относящимися к областиприложения (см. $$12.1.3 и $$12.4).При определении интерфейсов следует обратить внимание на те классы, где набор операцийпредставлен более, чем на одном уровне абстракции. Например, в классе file у некоторых функцийчленов аргументы имеют тип file_descriptor (дескриптор_файла), а у других аргументы - строкасимволов, которая обозначает имя файла. Операции с file_descriptor работают на другом уровне(меньшем) абстракции, чем операции с именем файла, так что даже странно, что они относятся кодному классу.
Возможно, было бы лучше иметь два класса: один представляет понятие дескрипторафайла, а другой - понятие имени файла. Обычно все операции класса должны представлять понятияодного уровня абстракции. Если это не так, то стоит подумать о реорганизации и его, и связанных с нимклассов.11.3.3.5 Перестройка иерархии классовШаги 1 и 3 требуют исследования классов и их иерархии, чтобы убедиться, что они адекватно отвечаютнашим требованиям. Обычно это не так, и приходится проводить перестройку для улучшенияструктуры, проекта или реализации.Самая типичная перестройка иерархии классов состоит в выделении общей части двух классов в новыйкласс или в разбиении класса на два новых.
В обоих случаях в результате получится три класса:базовый класс и два производных. Когда следует проводить такую перестройку? Каковы общиепоказания, что такая перестройка будет полезной?К сожалению нет простого и универсального ответа на эти вопросы. Это и не удивительно, посколькуто, что предлагается, не является мелочью при реализации, а изменяет основные понятия системы.Важной и нетривиальной задачей является поиск общности среди классов и выделение общей части.Нет точного определения общности, но следует обращать внимание на общность для понятий системы,а не просто для удобства реализации. Указаниями, что два класса имеют нечто общее, что возможновыделить в общий базовый класс, служат схожие способы использования, сходство наборов операций,сходство реализаций и просто тот факт, что часто в процессе обсуждения проекта обаклассапоявляются одновременно.
С другой стороны, если есть несколько наборов операций класса сразличными способами использования, если эти наборы обеспечивают доступ к раздельнымподмножествам объектов реализации, и, если класс возникает в процессе обсуждения несвязанныхтем, то этот класс является явным кандидатом для разбиения на части.В силу тесной связи между понятиями и классами проблемы перестройки иерархии классоввысвечиваются на поверхности проблем именования классов и использования имен классов в процессеобсуждения проекта.
Если имена классов и их упорядоченность, задаваемая иерархией классов,кажутся неудобными при обсуждении проекта, значит, по всей видимости, есть возможность улучшенияиерархии. Заметим, что подразумевается, что анализ иерархии классов лучше проводить не в одиночку.Если вы оказались в таком положении, когда не с кем обсудить проект, хорошим выходом будетпопытаться составить учебное описание системы, используя имена классов.11.3.3.6 Использование моделейКогда пишешь статью, пытаешься найти подходящую для темы модель. Нужно не бросаться сразупечатать текст, а поискать статьи на сходные темы, вдруг найдется такая, которая может послужитьотправной точкой. Если ею окажется моя собственная статья, то можно будет использовать даже кускииз нее, изменяя по мере надобности другие части, и вводить новую информацию только там, гдетребует логика предмета.
Таким образом, исходя из первого издания, написана эта книга. Предельный295Бьерн Страуструп.Язык программирования С++случай такого подхода - это написание открытки-формуляра, где просто нужно указать имя и, возможно,добавить пару строк для придания "личного" отношения. По сути такие открытки пишутся с указаниемотличия от стандарта.Во всех видах творческой деятельности использование существующих систем в качестве моделей дляновых проектов является скорее правилом, а не исключением. Всегда, когда это возможно,проектирование и программирование должны основываться на предыдущих работах.
Это сокращаетстепени свободы для разработчика и позволяет сосредоточить внимание на меньшем числе вопросов взаданное время. Начать большой проект "практически с нуля" - это может возбуждать, но правильнеебудет употребить термин "опьянение", которое приведет к "пьяному блужданию" в множествевариантов. Построение модели не накладывает каких-либо ограничений и не означает покорногоследования ей, это просто освобождает разработчика от некоторых вопросов.Заметим, что на самом деле использование моделей неизбежно, поскольку каждый проектсинтезируется из опыта его разработчиков.