Литмир - Электронная Библиотека
A
A

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Программа обязательно должна быть понятной. Хорошим считается все, что помогает нам понимать программу и размышлять о ней. В принципе порядок лучше беспорядка, если только порядок не является результатом чрезмерного упрощения.

22.1.2.2. Общие подходы

Существуют два подхода к созданию правильного программного обеспечения.

• Снизу–вверх. Система компонуется только из составляющих частей, правильность которых уже доказана.

• Сверху–вниз. Система компонуется из составляющих частей, предположительно содержащих ошибки, а затем вылавливаются все ошибки.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Интересно, что наиболее надежные системы созданы с помощью сочетания обоих подходов, хотя они очевидным образом противоречат друг другу. Причина проста: для крупных реальных систем ни один из этих подходов не гарантирует требуемой правильности, адаптируемости и удобства сопровождения.

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

• Мы не можем полностью компенсировать недостатки основных компонентов (библиотек, подсистем, иерархий классов и т.д.), объединив их в законченную систему.

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

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Тестирование является существенной частью разработки программного обеспечения. Более подробно оно обсуждается в главе 26. Тестирование — это систематический поиск ошибок. Тестируйте как можно раньше и как можно чаще. Например, мы пытаемся разрабатывать наши программы так, чтобы упростить тестирование и помешать ошибкам скрыться в запутанном коде. 

22.1.2.3. Непосредственное выражение идей

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Когда мы выражаем какую-то идею — высоко- или низкоуровневую, — желательно выразить ее непосредственно в коде, а не устранять проблему обходным путем. Основной принцип выражения идей непосредственно в коде имеет несколько специфических вариантов.

Выражение идей непосредственно в коде. Например, аргумент лучше представлять с помощью специального типа (например,

Month
или
Color
), а не общего (например,
int
).

Независимое представление в коде независимых идей. Например, за некоторым исключением, стандартная функция

sort()
может упорядочивать любой стандартный контейнер любого элементарного типа; концепции сортировки, критерии сортировки контейнера и элементарный тип являются независимыми понятиями. Если бы мы должны были создать вектор объектов, расположенных в свободной памяти, элементы которого относятся к классу, выведенному из класса
Object
с функцией-членом
before()
, определенной для вызова из функции
vector::sort()
, то должны были бы иметь более узкую версию функции
sort()
, поскольку сделали предположения о хранении, иерархии классов, доступных функциях-членах, порядке и т.д.

Представление отношений между идеями непосредственно в коде. Наиболее общими отношениями, которые можно непосредственно выразить в коде, являются наследование (например, класс

Circle
является разновидностью класса
Shape
) и параметризация (например, класс
vector<T>
выражает нечто общее для всех векторов независимо от типа элементов).

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

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

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

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

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

 

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

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

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

305
{"b":"847443","o":1}