Файл: Руководство по стилю программирования и конструированию по.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 30.11.2023
Просмотров: 819
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
1 ... 45 46 47 48 49 50 51 52 ... 104
ГЛАВА 17 Нестандартные управляющие структуры
399
else {
importantVariable = GetValue();
MID_LOOP:
// Много кода.
}
Это хороший, логически извилистый пример: его практически невозможно чи- тать в том виде, в каком он есть, и тяжело правильно переписать без
goto. Если вам кажется, что вы легко преобразуете его в вариант без
goto, попросите кого- нибудь проверить ваш код! Несколько экспертов-программистов переписали его некорректно.
Вы можете изменить этот код разными способами. Можно продублировать код,
вынести общий код в отдельный метод и вызывать его из двух мест или повтор- но проверять одно и то же условие. В большинстве языков новая версия будет больше и медленнее оригинала, но совсем не намного. Поэтому, если этот код не исключительно критичен к скорости и объему, перепишите его, не задумываясь об эффективности.
Лучший способ переписать этот код — вынести участок
// Много кода в отдель- ный метод. После этого вы сможете вызывать его из тех мест, где раньше распо- лагались
goto и метка его перехода. Это позволит сохранить оригинальную струк- туру условного оператора. Вот как это выглядит:
Пример совместного использования кода в блоке else
с помощью вынесения общего кода в отдельный метод (C++)
if ( statusOk ) {
if ( dataAvailable ) {
importantVariable = x;
DoLotsOfCode( importantVariable );
}
}
else {
importantVariable = GetValue();
DoLotsOfCode( importantVariable );
}
В общем случае написание нового метода — лучший подход. Однако иногда вы- носить дублированный код в отдельный метод непрактично. В этом случае как обходной маневр можно предложить реструктурирование условных выражений так, чтобы оставить код в том же методе, а не выносить в отдельный:
Пример совместного использования кода в блоке else без применения goto (C++)
if ( ( statusOk && dataAvailable ) || !statusOk ) {
if ( statusOk && dataAvailable ) {
importantVariable = x;
}
400
ЧАСТЬ IV Операторы else {
importantVariable = GetValue();
}
// Много кода.
}
Это точное механическое преобразование логики вариан- та с
goto. Здесь переменная statusOK дополнительно прове- ряется два раза, а
dataAvailable — один, но сам код эквива- лентен. Если повторная проверка условия вас беспокоит, об- ратите внимание, что значение
statusOK не обязательно про- верять дважды в первом условии
if. Кроме того, вы также можете опустить про- верку
dataAvailable во втором условии if.
Краткий итог основных принципов использования goto
Использование
goto — это вопрос религии. Моя догма: в современных языках вы легко можете заменить девять из десяти операторов
goto эк- вивалентными последовательными конструкциями. В этих простых слу- чаях вы должны заменять операторы
goto просто по привычке. В сложных случа- ях вы также можете изгнать
goto в девяти случаях из десяти: можно разбить код на меньшие по размеру методы, использовать
try-finally или вложенные if, прове- рять и перепроверять статусную переменную или реструктурировать условные вы- ражения. Исключить
goto в таких случаях сложнее, но это хорошее умственное уп- ражнение, а методы, обсуждаемые в этом разделе, предлагают вам инструменты для этих целей.
В одном случае, оставшемся из 100, в котором применение
goto — вполне легаль- ное решение задачи, подробно задокументируйте, а затем используйте его. Если у вас на ногах резиновые сапоги, не стоит обходить весь квартал, чтобы не за- пачкаться в грязной луже. Но не отвергайте варианты избавления от
goto, предла- гаемые другими программистами. Они могут заметить то, на что вы не обратили внимания.
Вот сводка принципов использования
goto.
쐽
Применяйте
goto для эмуляции структурированных управляющих конструкций в языках, не поддерживающих их напрямую. Причем эмулируйте их точно — не злоупотребляйте дополнительной гибкостью, предоставляемой оператором
goto.
쐽
Не используйте
goto, если доступна эквивалентная встроенная конструкция.
쐽
Измеряйте производительность всех
goto, используемых для повышения эффективности. В большинстве случаев вы можете переписать код без
goto с целью повышения чита- бельности и при этом не потерять в эффективности. Если ваш случай — исключение, задокументируйе улучшение эффективности так,
чтобы поборники кода без
goto не удалили эти операторы, когда их увидят.
쐽
Ограничьтесь использованием одной метки
goto на метод, если только вы не эмулируете управляющие конструкции.
Перекрестная ссылка Иной под- ход к данной проблеме — ис- пользование таблицы решений
(см. главу 18).
Перекрестная ссылка О повы- шении эффективности см. гла- вы 25 и 26.
ГЛАВА 17 Нестандартные управляющие структуры
401
쐽
Используйте операторы
goto так, чтобы их переходы были только вперед, а не назад, если только вы не эмулируете управляющие конструкции.
쐽
Убедитесь, что используются все метки
goto. Неиспользуемые метки могут слу- жить признаком недописанного кода, а именно того, в котором осуществля- ется переход по этим меткам. Если метки не используются, удалите их.
쐽
Убедитесь, что
goto не приводит к созданию недостижимого кода.
쐽
Если вы менеджер, думайте о перспективе. Битва по поводу одного единствен- ного
goto не стоит поражения в целой войне. Если программист представляет себе альтернативы и готов к диалогу, то, возможно, использование
goto впол- не допустимо.
17.4. Перспективы нестандартных
управляющих структур
Время от времени кто-нибудь решает, что эти управляющие структуры — хоро- шая идея:
쐽
неограниченное использование операторов
goto;
쐽
возможность вычислять метку перехода
goto динамически и переходить по этому адресу;
쐽
возможность применения
goto для перехода из середины одного метода в се- редину другого;
쐽
возможность вызывать метод с помощью номера строки или метки, которые позволят начать выполнение с середины метода;
쐽
возможность генерации кода программой на лету и немедленного его выпол- нения.
В свое время каждая из этих идей считалась приемлемой или даже желательной,
хотя сейчас они все выглядят безнадежно устаревшими или опасными. Область разработки ПО развивается во многом благодаря
ограничению того, что програм- мисты могут делать со своим кодом. В связи с этим я рассматриваю нетрадици- онные управляющие структуры с большим скептицизмом. Я подозреваю, что боль- шинство конструкций, упомянутых в этой главе, со временем окажется на свалке программистских отходов наряду с вычисляемыми метками
goto, плавающими точками входа в методы, самомодифицирующимся кодом и другими структура- ми, отдающими предпочтение гибкости и удобству в ущерб структурированнос- ти и возможности управления сложностью.
Дополнительные ресурсы
Следующие материалы позволят расширить ваши представ- ления о нестандартных управляющих структурах.
Возвраты
Fowler, Martin.
Refactoring: Improving the Design of Existing Code. Reading, MA: Addison-
Wesley, 1999. В описании метода рефакторинга под названием «Замените вложенные http://cc2e.com/1792
402
ЧАСТЬ IV Операторы условные выражения сторожевыми операторами» Фаулер предлагает использовать множественные возвраты из методов для уменьшения вложенности набора
if-вы- ражений. Фаулер приводит доводы в защиту того, что множественные операторы
return — подходящий способ улучшения ясности кода и нет никакого вреда в том,
чтобы иметь несколько выходов из метода.
Операторы goto
Следующие статьи содержат полное обсуждение
goto. Этот спор до сих пор воз- никает время от времени на рабочих местах, в учебниках и журналах, но вы не услышите ничего такого, что не было бы полностью исследовано 20 лет назад.
Dijkstra, Edsger. «Go To Statement Considered Harmful».
Com-
munications of the ACM 11, no. 3 (March, 1968): 147–148, так- же доступно по адресу
www.cs.utexas.edu/users/EWD/. Это то самое знаменитое письмо, которым Дейкстра поднес спичку к бумаге и воспла- менил одну из самых долгих дискуссий в истории разработки ПО.
Wulf, W. A. «A Case Against the GOTO».
Proceedings of the 25th National ACM Confer-
ence, August 1972: 791–797. Эта статья — еще один аргумент против беспорядоч- ного использования
goto. Вульф утверждает, что, если языки программирования будут содержать необходимые управляющие структуры, необходимость в
goto
исчезнет. С 1972 г., когда была написана эта статья, такие языки, как C++, Java и
Visual Basic, доказали свою корректность по Вульфу.
Knuth, Donald. «Structured Programming with go to Statements», 1974.
Classics in
Software Engineering, edited by Edward Yourdon. Englewood Cliffs, NJ: Yourdon Press,
1979. Эта длинная статья не полностью посвящена
goto, но содержит кучу приме- ров кода, который становится эффективнее после исключения
goto, и еще одну кучу примеров кода, который становится эффективней после добавления
goto.
Rubin, Frank. «‘GOTO Considered Harmful’ Considered Harmful».
Communications of
the ACM 30, no. 3 (March, 1987): 195–196. В этой несколько резкой статье, обра- щенной к редактору, Рубин утверждает, что программирование без
goto стоило бизнесу «сотни миллионов долларов». Затем он предлагает краткий фрагмент кода,
использующего
goto, и утверждает, что он превосходит свои аналоги без goto.
Ответы, полученные на письмо Рубина, представляют больший интерес, чем само письмо. Пять месяцев журнал «Communications of the ACM» (CACM) публиковал письма, предлагающие разные версии программы Рубина из семи строк. Ответы равномерно распределились между защитниками и хулителями
goto. Читатели предложили приблизительно 17 вариантов преобразования, которые полностью покрывают все подходы к исключению
goto. Редактор CACM заметил, что это письмо вызвало больше откликов, чем любой другой вопрос, когда-либо обсуждавшийся на страницах CACM.
Последовавшие письма можно найти в номерах:
쐽
Communications of the ACM 30, no. 5 (May, 1987): 351–355;
쐽
Communications of the ACM 30, no. 6 (June, 1987): 475–478;
쐽
Communications of the ACM 30, no. 7 (July, 1987): 632–634;
쐽
Communications of the ACM 30, no. 8 (August, 1987): 659–662;
쐽
Communications of the ACM 30, no. 12 (December, 1987): 997, 1085.
http://cc2e.com/1799
ГЛАВА 17 Нестандартные управляющие структуры
403
Clark, R. Lawrence, «A Linguistic Contribution of GOTO-less
Programming».
Datamation, December 1973. Эта классическая статья с юмором предлагает заменить термин «go to» (пе- рейти к) на «come from» (перешел от). Она также была перепечатана в номере CACM
в апреле 1974 года.
Контрольный список: нестандартные
управляющие структуры
Возвраты
Используют ли методы операции возврата только при необходимости?
Улучшают ли операторы возврата читабельность?
Рекурсия
Содержит ли рекурсивный метод код для прекращения рекурсии?
Использует ли метод счетчик безопасности для гарантии того, что выпол- нение будет завершено?
Ограничена ли рекурсия одним методом?
Соответствует ли глубина рекурсии ограничениям, налагаемым размерами стека программы?
Является ли рекурсия лучшим способом реализации метода? Не лучше ли использовать простые итерации?
goto
Используются ли операторы goto только как последнее средство и лишь для того, чтобы сделать код удобнее для чтения и сопровождения?
Если goto используется ради эффективности, был ли прирост эффективно- сти измерен и задокументирован?
Ограничено ли использование goto одной меткой на метод?
Выполняются ли переходы goto только вперед, а не назад?
Все ли метки goto используются?
Ключевые моменты
쐽
Множественные возвраты могут улучшить читабельность и сопровождаемость метода и помогают избежать глубокой вложенности. Тем не менее использо- вать их нужно осторожно.
쐽
Рекурсия предлагает изящное решение для небольшого набора задач. Ее тоже нужно использовать аккуратно.
쐽
Иногда операторы
goto — лучший способ облегчить чтение и сопровождение кода. Таких случаев очень немного. Используйте
goto только как последнее средство.
http://cc2e.com/1706
http://cc2e.com/1713
404
ЧАСТЬ IV Операторы
Г Л А В А 1 8
Табличные методы
Содержание
쐽
18.1. Основные вопросы использования табличных методов
쐽
18.2. Таблицы с прямым доступом
쐽
18.3. Таблицы с индексированным доступом
쐽
18.4. Таблицы со ступенчатым доступом
쐽
18.5. Другие примеры табличного поиска
Связанные темы
쐽
Сокрытие информации: подраздел «Скрывайте секреты (к вопросу о сокрытии информации)» раздела 5.3
쐽
Проектирование классов: глава 6
쐽
Использование таблиц решений для замены сложной логики: раздел 19.1
쐽
Замена сложных выражений табличным поиском: раздел 26.1
Табличный метод — это схема, позволяющая искать информацию в таблице, а не использовать для этого логические выражения, такие как
if и case. Практически все, что вы можете выбирать посредством логических операторов, можно выби- рать, применяя таблицы. В простых случаях логические выражения проще и по- нятней. Но при усложнении логических построений таблицы становятся все при- влекательнее.
Если вы уже знакомы с табличными методами, считайте эту главу обзором. В этом случае вы можете изучить «Пример гибкого формата сообщения» (раздел 18.2)
в качестве иллюстрации того факта, что объектно-ориентированный дизайн не обязательно лучше других вариантов только потому, что он объектно-ориенти- рованный. После этого можете переходить к обсуждению общих вопросов управ- ления в главе 19.
http://cc2e.com/1865