Файл: Руководство по стилю программирования и конструированию по.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 30.11.2023
Просмотров: 803
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
726
ЧАСТЬ VII Мастерство программирования
Листинг 31-19. Пример применения begin и end в качестве
границ блока switch/case (C++)
switch ( pixelColor )
{
case Color_Red:
statement1;
statement2;
break;
case Color_Green:
statement1;
statement2;
break;
default:
statement1;
statement2;
break;
}
Такой стиль выравнивания также вполне функционален и согласуется с Основ- ной теоремой форматирования (напомним: он показывает логическую структу- ру, лежащую в основе данного кода). Единственное его ограничение в том, что его нельзя применять буквально в операторах
switch/case в C++ и Java, что пока- зано в листинге 31-19. (Ключевое слово
break служит заменой закрывающей скобке,
а у открывающей скобки нет эквивалента.)
Форматирование в конце строки
Еще одна стратегия форматирования называется «форматированием в конце стро- ки», и объединяет большую группу методик, в которых отступ в коде делается к середине или концу строки. Отступы в конце строки служат для выравнивания блока относительно ключевого слова, с которого он начинается, выравнивания следующих параметров метода под первым параметром, размещения вариантов в операторе
case и подобных случаев. Листинг 31-20 представляет абстрактный пример:
Листинг 31-20. Абстрактный пример стиля форматирования в конце строки
A XXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXX
B XXXXXXXXXXXXXXX
C XXXXXXXXXXXXXXX
D XX
В этом примере оператор A начинает управляющую конструкцию, а оператор D
завершает. Операторы B, C и D выровнены под ключевым словом, с которого на- чинается блок в операторе A. Одинаковые отступы B, C и D показывают, что эти операторы сгруппированы вместе. Листинг 31-21 содержит менее абстрактный пример кода, отформатированного в соответствии с этой стратегией:
ГЛАВА 31 Форматирование и стиль
727
Листинг 31-21. Пример форматирования в конце строки в блоке while (Visual Basic)
While ( pixelColor = Color_Red )
statement1;
statement2;
Wend
В этом примере
end помещен в конец строки, а не под соответствующим ключе- вым словом. Некоторые предпочитают располагать
end под ключевым словом, но выбор между этими двумя вполне приемлемыми вариантами — наименьшая из проблем этого стиля.
Стиль форматирования в конце строки иногда работает вполне удовлетворительно.
Листинг 31-22 демонстрирует пример, в котором этот стиль работает:
Листинг 31-22. Редкий пример, в котором форматирование
в конце строки выглядит привлекательно (Visual Basic)
If ( soldCount > 1000 ) Then markdown = 0.10
profit = 0.05
Ключевое слово else выровнено относительно слова then, расположенного над ним.
Else markdown = 0.05
End If
В этом случае ключевые слова
Then, Else и End If выровнены, и код, следующий за ними,
также выровнен. Визуальный эффект соответствует ясной логической структуре.
Критически взглянув на приводимый ранее пример
case-оператора, вы, вероят- но, сможете указать на недостаток данного стиля. По мере усложнения условного выражения этот стиль начнет давать бесполезные или обманчивые подсказки о логической структуре кода. В листинге 31-23 приведен пример ухудшения этого стиля при его применении в более сложном условном выражении:
Листинг 31-23. Более типичный пример, в котором
форматирование в конце строки является неудачным решением (Visual Basic)
If ( soldCount > 10 And prevMonthSales > 10 ) Then
If ( soldCount > 100 And prevMonthSales > 10 ) Then
If ( soldCount > 1000 ) Then markdown = 0.1
profit = 0.05
Else markdown = 0.05
End If
Else markdown = 0.025
End If
Else markdown = 0.0
End If
>
728
ЧАСТЬ VII Мастерство программирования
В чем причина причудливого форматирования выражений
Else в конце примера?
Они последовательно выровнены под соответствующими ключевыми словами, но вряд ли можно утверждать, что такие отступы проясняют логическую структуру.
И если при модификации кода изменится длина первой строки, такой стиль фор- матирования потребует изменения отступов во всех соответствующих выражениях.
Так что возникает проблема сопровождения, которой не существует для стилей явных блоков, их эмуляции и использования пар
begin-end для обозначения гра- ниц блоков.
Вы можете решить, что эти примеры придуманы лишь в демонстрационных це- лях, но такой стиль применяется очень упорно, несмотря на все его недостатки.
Масса учебников и справочников по программированию рекомендует этот стиль.
Самая первая увиденная мной книга, содержащая эту рекомендацию, была опуб- ликована в середине 1970-х, последняя — в 2003 году.
Вообще форматирование в конце строки неаккуратно, его сложно применять еди- нообразно и тяжело сопровождать. Далее я приведу другие проблемы такого стиля.
Какой стиль наилучший?
При работе в Visual Basic используйте отступы для явных блоков (тем более что в среде разработки Visual Basic затруднительно не придерживаться этого стиля).
В Java стандартной практикой является применение формата явных блоков.
В C++ можно просто выбрать тот стиль, который вам больше нравится или кото- рому отдают предпочтение большинство разработчиков вашей команды. Как эмуля- ция явных блоков, так и обозначение границ с помощью
begin-end работает оди- наково хорошо. Единственное исследование, сравнивавшее эти два стиля, не об- наружило статистически значимых различий между ними с точки зрения понят- ности кода (Hansen and Yim, 1987).
Ни один из этих стилей не обеспечивает защиты от дурака, и оба время от време- ни требуют «разумного и очевидного» компромисса. Вы можете предпочесть тот или иной стиль по эстетическим причинам. В этой книге в примерах кода при- меняется стиль явных блоков, так что вы можете увидеть массу иллюстраций это- го стиля, просто просмотрев листинги. Выбрав однажды стиль, вы получите наи- большую выгоду от хорошего форматирования, применяя его единообразно.
31.4. Форматирование управляющих структур
Форматирование некоторых программных элементов час- то является только эстетическим вопросом. Однако форма- тирование управляющих структур влияет на удобство чте- ния и понимания и поэтому имеет практическое значение.
Тонкие моменты форматирования
блоков управляющих структур
Работа с блоками управляющих структур требует внимания к деталям. Вот неко- торые советы.
Перекрестная ссылка О доку- ментировании управляющих структур см. подраздел «Ком- ментирование управляющих структур» раздела 32.5. О дру- гих аспектах управляющих структур см. главы 14–19.
ГЛАВА 31 Форматирование и стиль
729
Избегайте отсутствия отступов в парах begin-end В стиле форматиро- вания, проиллюстрированном в листинге 31-24, пара
begin-end выровнена по гра- нице управляющей структуры, а в выражениях, охватываемых операторами
begin
и
end, сделаны отступы относительно begin.
Листинг 31-24. Пример пары begin-end, не выделенной отступами (Java)
Ключевое слово begin выровнено по границе for.
for ( int i = 0; i < MAX_LINES; i++ )
{
В выражениях сделан отступ относительно begin.
ReadLine( i );
ProcessLine( i );
Слово end также выровнено по границе структуры for.
}
Хотя такой подход выглядит хорошо, он нарушает Основную теорему формати- рования, так как не показывает логическую структуру кода. При таком располо- жении
begin и end не являются частью управляющей структуры, но в то же время,
они не являются и частью блока выражений, расположенного далее.
Листинг 31-25 демонстрирует абстрактное представление этого подхода:
Листинг 31-25. Абстрактный пример вводящего в заблуждение выравнивания
A XXXXXXXXXXXXXXXXXXXX
B XXXXXXX
C XXXXXXXX
D XXXXXXXXXXXXXX
E XXXX
Можно ли сказать, что оператор B подчиняется оператору A? Он не выглядит ча- стью оператора A, и нет оснований считать, что он ему подчиняется. Если вы используете такой подход, смените его на один из двух вариантов стиля, описан- ных ранее, и ваше форматирование будет более целостным.
Избегайте двойных отступов при использовании begin и end Следствием правила относительно использования пары
begin-end без отступов является слу- чай, касающийся дополнительных отступов после
begin-end. Этот стиль, продемон- стрированный в листинге 31-26, содержит отступы как перед
begin и end, так и перед выражениями, которые они охватывают:
Листинг 31-26. Пример неуместного двойного отступа
в блоке begin-end (Java)
for ( int i = 0; i < MAX_LINES; i++ )
{
>
>
>
730
ЧАСТЬ VII Мастерство программирования
В выражениях после begin сделан лишний отступ.
ReadLine( i );
ProcessLine( i );
}
Еще один пример стиля, внешне привлекательного, но нарушающего Основную теорему форматирования. Исследования показали, что с точки зрения понимания программы, использующие одинарные и двойные отступы, не отличаются друг от друга (Miaria et al., 1983), но приведенный стиль неточно отображает логическую структуру программы.
ReadLine() и ProcessLine() показаны так, будто они подчи- нены паре
begin-end, что не соответствует действительности.
Этот подход также преувеличивает сложность логической структуры программы.
Какая из структур, приведенных в листингах 31-27 и 31-28, выглядит сложнее?
Листинг 31-27. Абстрактная структура 1
XXXXXXXXXXXXXXXXXXXX
XXXXX
XXXXXXXXX
XXXXXXXXXXXX
XXXXX
Листинг 31-28. Абстрактная структура 2
XXXXXXXXXXXXXXXXXXXX
XXXXX
XXXXXXXXXX
XXXXXXXXXXXXX
XXXXX
Обе являются абстрактными представлениями структуры цикла
for. Структура 1
выглядит сложней, хотя и представляет тот же код, что и Структура 2. Если бы вам понадобилось создать 2 или 3 уровня вложенности операторов, то из-за двойных отступов вы получили бы 4 или 6 уровней отступов. Такое форматирование вы- глядело бы сложнее, чем на самом деле. Избавьтесь от этой проблемы, эмулиро- вав явные блоки или применив
begin и end в качестве границ блока, выравнивая
begin и end так же, как и выражения, которые они охватывают.
Другие соглашения
Хотя отступы в блоках являются главным вопросом форматирования управляю- щих структур, вы также можете столкнуться с другими проблемами, поэтому да- лее я привожу еще несколько советов.
Используйте пустые строки между абзацами Некоторые блоки не разгра- ничиваются с помощью пар
begin-end. Логический блок — группа подходящих друг к другу операторов — должны рассматриваться так же, как абзацы в обычной книге.
Отделяйте их друг от друга с помощью пустых строк. Листинг 31-29 представля- ет пример абзацев, которые следует разделить:
>
1 ... 82 83 84 85 86 87 88 89 ... 104
ГЛАВА 31 Форматирование и стиль
731
Листинг 31-29. Пример кода, который следует сгруппировать
и разбить на абзацы (C++)
cursor.start = startingScanLine;
cursor.end = endingScanLine;
window.title = editWindow.title;
window.dimensions = editWindow.dimensions;
window.foregroundColor = userPreferences.foregroundColor;
cursor.blinkRate = editMode.blinkRate;
window.backgroundColor = userPreferences.backgroundColor;
SaveCursor( cursor );
SetCursor( cursor );
Этот код выглядит неплохо, но пустые строки позволят улуч- шить его с двух точек зрения. Во-первых, если у вас есть груп- па операторов, не требующих выполнения в определенном порядке, заманчиво объединить их именно так. Вам не надо усовершенствовать порядок выражений для помощи компь- ютеру, но читатели-люди оценят дополнительные подсказ- ки о том, какие операторы выполнять в определенном порядке, а какие — просто расположены рядом друг с другом. Дисциплина добавления пустых строк в коде программы заставляет вас тщательней обдумывать вопрос, какие операторы на самом деле подходят друг другу. Исправленный фрагмент кода, представленный в листинге
31-30, показывает, как организовать данный набор операторов.
Листинг 31-30. Пример кода, который правильно сгруппирован
и разбит на абзацы (C++)
Эти строки настраивают текстовое окно.
window.dimensions = editWindow.dimensions;
window.title = editWindow.title;
window.backgroundColor = userPreferences.backgroundColor;
window.foregroundColor = userPreferences.foregroundColor;
Эти строки устанавливают параметры курсора и должны быть отделены от предыдущих строк.
cursor.start = startingScanLine;
cursor.end = endingScanLine;
cursor.blinkRate = editMode.blinkRate;
SaveCursor( cursor );
SetCursor( cursor );
Реорганизованный код подчеркивает выполнение двух разных действий. В пер- вом примере недостатки организации операторов, отсутствие пустых строк, а также старый трюк с выравниванием знаков равенства приводили к тому, что выраже- ния выглядели связанными сильнее, чем на самом деле.
Второе преимущество использования пустых строк, приводящее к улучшению кода,
заключается в появлении естественного промежутка для добавления комментариев.
В листинге 31-30 комментарии над каждым блоком станут отличным дополнени- ем к улучшенному формату.
>
>
Перекрестная ссылка Если вы придерживаетесь Процесса про- граммирования с псевдокодом,
ваш код автоматически разби- вается на абзацы (см. главу 9).
732
ЧАСТЬ VII Мастерство программирования
Форматируйте блоки из одного оператора единообразно Блоком из од- ного оператора называется единственный оператор, следующий за управляющей структурой, например, оператор, который следует за проверкой условия
if. В этом случае для корректной компиляции пара
begin и end необязательна, и вы можете выбрать один из трех вариантов стиля, показанных в листинге 31-31:
Листинг 31-31. Пример вариантов стиля для блоков из одного оператора (Java)
Стиль 1
if ( expression )
один-оператор;
Стиль 2а if ( expression ) {
один-оператор;
}
Стиль 2б if ( expression )
{
один-оператор;
}
Стиль 3
if ( expression ) один-оператор;
Существуют аргументы в защиту каждого из этих трех подходов. Стиль 1 следует схеме отступов, используемой для блоков, поэтому он согласуется с остальными подходами. Стиль 2 (как 2а, так и 2б) также не противоречит общим правилам, а пары
begin-end уменьшают вероятность добавления операторов после условия if,
не указав
begin и end. Это станет особенно трудноуловимой ошибкой, потому что отступы будут подсказывать вам, что все в порядке, однако компилятор не интер- претирует отступы. Основное преимущества Стиля 3 над Стилем 2 в том, что его легче набирать. Его преимущество над стилем 1 в том, что при копировании в другую часть программы он с большей вероятностью будет скопирован правиль- но. А недостаток в том, что при использовании построчного отладчика такая строка будет рассматриваться как одно целое и вы не узнаете, выполняется ли выраже- ние после проверки условия
if.
Я использовал Стиль 1 и много раз становился жертвой неправильной модифи- кации. Мне не нравится нарушение стратегии отступов в Стиле 3, поэтому его я тоже избегаю. В групповых проектах я предпочитаю вариации Стиля 2 из-за по- лучаемого единообразия и возможности безопасной модификации. Независимо от избранного стиля применяйте его последовательно и используйте один и тот же стиль в условиях
if и во всех циклах.
В сложных выражениях размещайте каждое условие на отдельной строке
Размещайте каждую часть сложного выражения на отдельной строке. Листинг 31-32
содержит пример выражения, форматированного без учета удобочитаемости:
>
>
>
>