Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

• Простое выражение простых идей. Следование принципам, сформулированным выше, может привести к созданию кода, носящего слишком общий характер. Например, мы можем столкнуться с иерархией классов с более сложной таксономией (структурой наследования), чем требуется, или с семью параметрами для каждого (очевидно) простого класса. Для того чтобы избежать возможных осложнений, мы пытаемся создавать простые версии для наиболее распространенных или наиболее важных ситуаций. Например, кроме общей версии функции

sort(b,e,op)
, сортирующей элементы с помощью оператора
op
, существует вариант
sort(b,e)
, выполняющий неявную сортировку с помощью отношения “меньше”. Если бы мы могли (или имели возможность использовать язык C++0x; см. раздел 22.2.6), то предусмотрели бы также версию
sort(c)
для сортировки стандартного контейнера с помощью отношения “меньше” и функцию
sort(c,op)
для сортировки стандартного контейнера с помощью оператора
op
.

22.1.2.4. Уровень абстракции

Мы предпочитаем работать на максимально возможном уровне абстракции, иначе говоря, стремимся выражать свои решения в как можно более общем виде.

Рассмотрим, например, как представлены записи в телефонной книге, которая может храниться в вашем мобильном телефоне. Мы могли бы представить множество пар (имя, значение) с помощью класса

vector<pair<string,Value_type>>
. Однако если мы почти всегда обращаемся к этому множеству для поиска имени, то более высокий уровень абстракции обеспечит нам класс
map<string,Value_type>
. Это позволит не писать (и отлаживать) функции доступа к записям. С другой стороны, класс
vector<pair<string,Value_type>>
сам по себе находится на более высоком уровне абстракции, чем два массива,
string[max]
и
Value_type[max]
, где отношение между строкой и значением носит неявный характер. На самом низком уровне абстракции могло бы находиться сочетание типа
int
(количество элементов) и двух указателей
void*
(ссылающихся на какую-то форму записи, известную программисту, но не компилятору). В нашем примере каждое из предложенных решений можно отнести к низкому уровню абстракции, поскольку в каждом из них основное внимание сосредоточено на представлении пар значений, а не на их функциях. Для того чтобы приблизиться к реальному приложению, следует определить класс, который непосредственно отражает способ его использования. Например, мы могли бы написать код приложения, используя класс
Phonebook
с удобным интерфейсом. Класс
Phonebook
можно было бы реализовать с помощью одного из описанных выше представлений данных.

Причина, по которой мы предпочитаем оставаться на высоком уровне абстракции (если в нашем распоряжении есть соответствующий механизм абстракций и наш язык поддерживает его на приемлемом уровне эффективности), заключается в том, что такие формулировки ближе к нашим размышлениям о задаче и ее решениях, чем решения, выраженные в терминах аппаратного обеспечения компьютера.

Как правило, основной причиной перехода на низкий уровень абстракции называют эффективность. Однако это следует делать только в случае реальной необходимости (раздел 25.2.2). Использование низкоуровневых (более примитивных) языковых свойств не всегда повышает производительность программы. Иногда оно исключает возможности оптимизации. Например, используя класс

Phonebook
, можем выбрать способ его реализации, например, в виде сочетания массивов
string[max]
и
Value_type[max]
или в виде класса
map<string,Value_type>
. Для одних приложений более эффективным оказывается первый вариант, а для других — второй. Естественно, производительность не является основным фактором, если вы пишете программу для хранения записей из своей телефонной книжки. Но оно становится существенным, если необходимо хранить и обрабатывать миллионы записей. Что еще важнее, использование низкоуровневых средств сопряжено с затратами рабочего времени, которого программисту не хватит на усовершенствование (повышение производительности или чего-то другого).

22.1.2.5. Модульность

Модульность — это принцип. Мы хотим составлять наши системы из компонентов (функций, классов, иерархий классов, библиотек и т.д.), которые можно создавать, анализировать и тестировать по отдельности. В идеале нам также хотелось бы проектировать и реализовывать такие компоненты таким образом, чтобы их можно было использовать в нескольких программах (повторно). Повторное использование (reuse) — это создание систем из ранее протестированных компонентов, которые уже были использованы где-то, а также проектирование и применение таких компонентов. Мы уже касались этой темы, обсуждая классы, иерархии классов, проектирование интерфейсов и обобщенное программирование. Большинство из того, что мы говорили о стилях программирования в разделе 22.1.3, связано с проектированием, реализацией и использованием компонентов, допускающих повторное использование. Следует подчеркнуть, что не каждый компонент можно использовать в нескольких программах; некоторые программы являются слишком специализированными, и их нелегко приспособить для использования в других условиях.

Модульность кода должна отражать основные логические разделы приложения. Не следует повышать степень повторного использования, просто погружая два совершенно разных класса А и В в повторно используемый компонент C. Объединение интерфейсов классов A и B в новом модуле C усложняет код.

Здесь оба пользователя используют модуль С. Пока вы не заглянете внутрь модуля С, вы можете подумать, что оба пользователя получают преимущества благодаря тому, что совместно используют общедоступный компонент. Выгоды от совместного использования (повторного) могут (в данном случае этого не происходит) включать в себя более легкое тестирование, меньший объем кода, расширения пользовательской базы и т.д. К сожалению, за исключением случая излишнего упрощения, это не редкая ситуация.

Чем можно помочь? Может быть, следует создать общий интерфейс классов А и В?

Эти диаграммы подсказывают, что следует использовать наследование и параметризацию соответственно. В обоих случаях, для того чтобы работа имела смысл, интерфейс должен быть меньше, чем простое объединение интерфейсов классов А и В. Иначе говоря, для того чтобы пользователь получил выгоду от принятого решения, классы А и В должны иметь фундаментальную общность. Обратите внимание на то, что мы снова вернулись к интерфейсам (см. разделы 9.7 и 25.4.2) и, как следствие, к инвариантам (см. раздел 9.4.3).

22.1.2.6. Логичность и минимализм

Логичность и минимализм — основные принципы выражения идей. Следовательно, мы можем забыть о них, как о вопросах, касающихся внешней формы. Однако запутанный проект очень трудно реализовать элегантно, поэтому требование логичности и минимализма можно рассматривать как критерии проектирования, влияющие на большинство мельчайших деталей программы.

• Не добавляйте свойство, если сомневаетесь в его необходимости.

• Похожие свойства должны иметь похожие интерфейсы (и имена), но только если их сходство носит фундаментальный характер.

• Непохожие свойства должны иметь непохожие имена (и по возможности разные интерфейсы), но только если их различие носит фундаментальный характер

Логичное именование, стиль интерфейса и стиль реализации облегчают эксплуатацию программы. Если код логичен, то программист не будет вынужден изучать новый набор соглашений, касающихся каждой части крупной системы. Примером является библиотека STL (см. главы 20-21, раздел Б.4–6). Если обеспечить логичность не удается (например, из-за наличия старого кода или кода, написанного на другом языке), то целесообразно создать интерфейс, который обеспечит согласование стиля с остальной частью программы. В противном случае этот чужеродный (“странный”, “плохой”) код “заразит” каждую часть программы, вынужденную к нему обращаться.

  • Читать дальше
  • 1
  • ...
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: