Главная страница
Навигация по странице:

  • Переписать с помощью

  • Код, избавившийся от goto с помощью try-finally (Visual Basic)

  • Сравнение рассмотренных подходов

  • Операторы goto и совместное использование кода в блоке else

  • Пример совместного использования кода в блоке else с помощью goto (C++)

  • Пример совместного использования кода в блоке else с помощью вынесения общего кода в отдельный метод (C++)

  • Пример совместного использования кода в блоке else без применения goto (C++)

  • Краткий итог основных принципов использования goto

  • Перекрестная ссылка

  • 17.4. Перспективы нестандартных управляющих структур

  • Дополнительные ресурсы Следующие материалы позволят расширить ваши представления о нестандартных управляющих структурах.Возвраты

  • Контрольный список: нестандартные управляющие структуры Возвраты

  • ЧАСТЬ IV

  • Совершенный код. Совершенный код. Мастер-класс. Стив Макконнелл. Руководство по стилю программирования и конструированию по


    Скачать 5.88 Mb.
    НазваниеРуководство по стилю программирования и конструированию по
    АнкорСовершенный код
    Дата31.03.2023
    Размер5.88 Mb.
    Формат файлаpdf
    Имя файлаСовершенный код. Мастер-класс. Стив Макконнелл.pdf
    ТипРуководство
    #1028502
    страница51 из 106
    1   ...   47   48   49   50   51   52   53   54   ...   106
    ГЛАВА 17 Нестандартные управляющие структуры
    397
    дующие за проверкой
    if%then%else, ближе к месту самой проверки, чем в случае с вложенными
    if, и совсем не использует блоки else.
    Понимание версии с вложенными
    if требует некоторой умственной гимнастики.
    Вариант со статусной переменной легче для понимания, потому что лучше моде#
    лирует способ человеческого мышления. Вы ищете файл. Если все в порядке, вы открываете файл. Если все до сих пор в порядке, вы перезаписываете файл. Если все до сих пор в порядке…
    Недостаток этого подхода в том, что использование статусных переменных — не настолько распространенная практика, как хотелось бы. Подробно документируйте их применение, иначе некоторые программисты могут не понять, что вы имели в виду. В данном примере применение хорошо названных перечислимых типов оказывает существенную помощь.
    Переписать с помощью tryfinally Некоторые языки, включая Visual Basic и
    Java, предоставляют конструкцию
    try%finally, которая может быть использована для очистки ресурсов в случае ошибки.
    Чтобы переписать пример, используя подход с
    try%finally, поместите код, который должен проверять возможные ошибки, в блок
    try, а код очистки — в блок finally.
    Блок
    try задает область обработки исключений, а finally выполняет любое осво#
    бождение ресурсов. Блок
    finally будет вызываться всегда независимо от того, бу#
    дет ли сгенерировано исключение и будет ли это исключение
    перехвачено в ме#
    тоде
    PurgeFiles().
    Код, избавившийся от goto с помощью try-finally (Visual Basic)
    ‘ Этот метод стирает группу файлов. Исключения передаются вызывающей стороне.
    Sub PurgeFiles()
    Dim fileIndex As Integer
    Dim fileToPurge As Data_File
    Dim fileList As File_List
    Dim numFilesToPurge As Integer
    MakePurgeFileList( fileList, numFilesToPurge )
    Try fileIndex = 0
    While ( fileIndex < numFilesToPurge )
    fileIndex = fileIndex + 1
    FindFile( fileList( fileIndex ), fileToPurge )
    OpenFile( fileToPurge )
    OverwriteFile( fileToPurge )
    Erase( fileToPurge )
    Wend
    Finally
    DeletePurgeFileList( fileList, numFilesToPurge )
    End Try
    End Sub
    Этот подход предполагает, что все вызовы функций в случае ошибки генерируют исключения, а не возвращают коды ошибок.

    398
    ЧАСТЬ IV Операторы
    Преимущество подхода с применением
    try%finally в том, что он проще, чем с goto
    и не использует
    goto. Кроме того, он позволяет избежать глубоко вложенных струк#
    тур
    if%then%else.
    Ограничением данного варианта с
    try%finally является то, что он должен быть последовательно реализован во всем коде. Если бы предыдущий пример был ча#
    стью программы, использующей коды ошибок наряду с исключениями, то коду исключения пришлось бы устанавливать код ошибки для всех возможных оши#
    бок, и это требование сделало бы фрагмент примерно таким же сложным, как и другие варианты.
    Сравнение рассмотренных подходов
    В защиту каждой из четырех приведенных методик есть что сказать. Подход с
    goto позволяет избежать глубокой вложен#
    ности и ненужных проверок, но, увы, он содержит
    goto. Под#
    ход с вложенными
    if позволяет обойтись без goto, но его глу#
    бокая вложенность преувеличивает картину логической слож#
    ности метода. Подход со статусной переменной избегает
    goto
    и глубокой вложенности, но добавляет дополнительные про#
    верки. И, наконец, подход с
    try%finally тоже позволяет избе#
    жать как
    goto, так и глубокой вложенности, но доступен не во всех языках.
    Вариант с
    try%finally наиболее предпочтителен в языках, предоставляющих такую конструкцию и в системах, еще не стандартизовавших какой#то иной подход. Если этот вариант невозможен, то подход со статусной переменной немного предпоч#
    тительнее, чем
    goto и вложенные if, так как он читабельнее и лучше моделирует задачу, однако это не делает его лучшим во всех ситуациях.
    Все эти методики работают хорошо, если последовательно применяются ко все#
    му коду проекта. Рассмотрите все плюсы и минусы, а затем примите решение на уровне проекта о том, какой подход предпочесть.
    Операторы goto и совместное использование
    кода в блоке else
    Одна из возможных ситуаций, в которой некоторые программисты захотят ис#
    пользовать
    goto, — это случай, когда у вас есть две проверки условия и блок else и вы хотите выполнить код одного из условий и блока
    else. Вот пример варианта,
    который может кого#нибудь подвигнуть к использованию
    goto:
    Пример совместного использования кода
    в блоке else с помощью goto (C++)
    if ( statusOk ) {
    if ( dataAvailable ) {
    importantVariable = x;
    goto MID_LOOP;
    }
    }
    Перекрестная ссылка Полный список методик, которые мож- но применять в аналогичных ситуациях, перечислен в подраз- деле «Сводка методик уменьше- ния глубины вложенности» раз- дела 19.4.

    ГЛАВА 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

    1   ...   47   48   49   50   51   52   53   54   ...   106


    написать администратору сайта