Это понятие Single Entry, Single Exit (SESE) происходит от языков с явным управлением ресурсами , таких как C и ассемблер. В C такой код будет пропускать ресурсы:
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
На таких языках у вас есть три основных варианта:
Скопируйте код очистки.
Тьфу. Избыточность это всегда плохо.
Используйте, goto
чтобы перейти к коду очистки.
Это требует, чтобы код очистки был последним в функции. (И вот почему некоторые утверждают, что goto
имеет свое место. И оно действительно - в C.)
Введите локальную переменную и управляйте потоком управления через нее.
Недостатком является то, что управление потоком манипулируют с помощью синтаксиса (думаю break
, return
, if
, while
) намного легче следить , чем поток управления манипулируют через состояние переменных (поскольку эти переменные не имеют состояния , когда вы смотрите на алгоритме).
В сборке это даже страннее, потому что вы можете перейти к любому адресу в функции при вызове этой функции, что фактически означает, что у вас есть практически неограниченное количество точек входа в любую функцию. (Иногда это полезно. Такие приемы являются распространенным приемом для компиляторов для реализации this
настройки указателя, необходимой для вызова virtual
функций в сценариях множественного наследования в C ++.)
Когда вам приходится управлять ресурсами вручную, использование параметров входа или выхода из функции в любом месте приводит к более сложному коду и, следовательно, к ошибкам. Поэтому появилась школа мысли, которая распространяла SESE, чтобы получить более чистый код и меньше ошибок.
Однако, когда в языке есть исключения, (почти) любая функция может быть преждевременно закрыта в (почти) любой точке, поэтому вам все равно необходимо предусмотреть возможность преждевременного возврата. (Я думаю, что finally
в основном используется для этого в Java и using
(при реализации IDisposable
, в finally
противном случае) в C #; в C ++ вместо этого используется RAII .) После того, как вы это сделаете, вы не сможете не выполнить очистку после себя из-за раннего return
утверждения, так что, вероятно, самый сильный аргумент в пользу SESE исчез.
Это оставляет читабельность. Конечно, функция 200 LoC с полудюжиной return
операторов, случайно разбросанных по ней, не является хорошим стилем программирования и не подходит для читабельного кода. Но такую функцию было бы нелегко понять без этих преждевременных возвратов.
В тех языках, где ресурсы не управляются или не должны управляться вручную, нет смысла или нет смысла придерживаться старого соглашения SESE. OTOH, как я уже говорил выше, SESE часто делает код более сложным . Это динозавр, который (за исключением C) плохо вписывается в большинство современных языков. Вместо того, чтобы помочь пониманию кода, это мешает.
Почему Java-программисты придерживаются этого? Я не знаю, но из моего (вне) POV, Java взяла много соглашений из C (где они имеют смысл) и применила их к своему OO-миру (где они бесполезны или просто плохи), где теперь придерживается их, независимо от того, что стоит. (Как соглашение, чтобы определить все ваши переменные в начале области.)
Программисты придерживаются всевозможных странных обозначений по иррациональным причинам. (Глубоко вложенные структурные утверждения - «наконечники стрел» - в таких языках, как Паскаль, когда-то рассматривались как прекрасный код.) Применение чистых логических рассуждений к этому, кажется, не может убедить большинство из них отклониться от своих устоявшихся способов. Вероятно, лучший способ изменить такие привычки - это научить их делать то, что лучше, а не то, что принято. Вы, будучи учителем программирования, держите это в руках.:)