Лучше ли вызывать функцию, которая не имеет эффекта в этот момент, ЕСЛИ она улучшает ясность кода?

60

У меня есть три вида в моей программе (приложение для iOS). Только один из них когда-либо активен одновременно, поэтому я отключаю видимость для двух из них и переключаю видимость, когда пользователь нажимает кнопки. Представления инициализируются как видимые, поэтому я отключил видимость в коде, прежде чем показывается основной вид.

я могу сделать

[view1 setAlpha:0.0f];
[view2 setAlpha:0.0f];

для двух представлений, но теперь третий (тот, который должен быть виден в начале приложения) не рассматривается. Я положил

[view3 setAlpha:1.0f];

после первых двух, потому что я думаю, что это ясно показывает, что на самом деле есть три представления, а не два, как можно подумать при просмотре кода. Как другие программисты делают это? Это чисто предпочтения или есть какие-то соглашения?

Если вызов очень тяжелый, очевидно, что лучше не звонить, когда в этом нет необходимости, но я удивлялся мелочам, таким как мой пример.

Kevin
источник

Ответы:

134

У вас есть инвариант:

Только один вид (из 3) всегда активен (и виден).

Затем я предлагаю вам предоставить функцию для переключения активности и видимости ВСЕХ представлений одновременно:

[setActiveView viewID:2]

Эта функция будет:

  • проверьте, активен ли вид, избегая ненужной работы
  • установить вид как активный и видимый
  • установить другие 2 представления как неактивные и невидимые

Он имеет несколько преимуществ относительно необработанного вызова setVisibility:

  • дружественный: необоснованный вызов не создает проблемы с производительностью
  • оборонительный: его единственный параметр гораздо труднее испортить, тогда как для setVisibilityнего сложнее запомнить, что диапазон значений есть 0.0f - 1.0fи что только один должен быть установлен в1.0f
  • устойчивый: следующий парень не может случайно забыть одно из представлений
  • адаптируемый: добавление / удаление представления не требует тщательного изучения всего кода приложения, чтобы найти, где находятся переключатели, необходимо обновить одну функцию (эту)

В идеале, чтобы обеспечить соблюдение инварианта, никакая другая функция не должна мешать с этим параметром ...

Матье М.
источник
Отличное предложение. Я собираюсь сделать это с моим текущим примером. Но как быть, когда такой дизайн невозможен / не нужен? Или вы решаете на месте, что лучший способ справиться с этим?
Кевин
4
@ Кевин: Это действительно зависит. Иногда вы можете решить проблему, выполняя итерацию по коллекции, иногда нет, но ключевой принцип состоит в том, чтобы избежать дублирования и упростить сохранение инвариантов. Чем больше «ручных» действий нужно запомнить, чтобы все работало правильно, тем меньше у вас шансов, что все будет работать правильно. Я не хочу быть расплывчатым, но есть так много разных ситуаций, что, боюсь, «общее» правило просто сбило бы вас с пути.
Матье М.
23
«облегчить сохранение инвариантов» - это общее правило, которое стоит запомнить.
Гусдор
1
@ Тонни: Я не знаю, поощряет ли использование глобальной переменной "делать все правильно", но на самом деле, если вы точно знаете, какая из них была активной раньше, вам нужно всего лишь обновить два представления. Другое решение для каждого представления - помнить его видимость и setVisibilityничего не делать, если видимость уже запрошена, что снижает ответственность.
Матье М.
1
@MatthieuM. Я написал на скорую руку, но на самом деле я тоже это имел в виду. Если вы знаете предыдущее состояние, вам нужно всего лишь обновить 2 вида. Как запомнить это состояние - другое дело ;-). Что касается перемещения ответственности вниз: если класс представления не предусматривает этого, вам нужно будет обернуть класс в другой объект, просто чтобы добавить это свойство. Это чистое решение, но, возможно, немного излишним.
Тонни
12

Альтернативная идея: если ваша цель состоит в том, чтобы предотвратить возникновение ошибок, потому что люди забывают, что есть три представления, и делают что-то только с двумя из них, что им действительно следует делать со всеми из них, тогда сделайте функцию, которая сделает невозможным забывание:

setViewVisibilities(0.0f, 0.0f, 1.0f)

Теперь у вас есть нечто гораздо более мощное - время компиляции гарантирует, что вы не забыли . Если вы забудете параметр, компилятор будет кричать на вас. Это гораздо полезнее, чем комментарии или ненужный код, так как создает строгий именованный протокол, который обеспечивает соблюдение свойства, о котором вы заботитесь.

В случае, когда view3не нужно менять видимость, вы можете добавить некоторое поведение, когда передача специального значения, такого как -1.0или, nilили что-то подобное, означает «вообще не изменяйте видимость представления». Это обходит проблему установки видимости без необходимости.

Джек
источник
9
Если OP получает до 10+ просмотров, параметр для просмотра станет невозможным для поддержки. Ваша точка зрения по поводу ошибок во время компиляции верна, но это, к сожалению, очень недостижимое решение.
Крис Cirefice
3
@ChrisCirefice: если количество представлений растет, вы можете создать какой-то объект / класс ViewState, который реализует этот инвариант. Затем используйте это для переключения и т. Д. При таком большом количестве представлений какой-либо объект менеджера, вероятно, имеет смысл в любом случае.
слеске
8

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

(возможно, тот факт, что вызов не нужен, или что вам нужен комментарий об этом, может быть запахом кода)

Василий Старынкевич
источник
1
@Niall Если возможно, утверждение будет даже лучше, чем комментарий.
200_success
9
Комментарии не являются решением проблемы не поддерживаемого и нечитаемого кода
dj18
2
@Kevin, или вы могли бы написать код, который будет отлично читаться без комментариев.
Jan
1
@Jan Комментарии - это больше, чем просто объяснение того, что делает код .......
Кевин
2
@Kevin Я бы сказал, что комментарии никогда не должны существовать, чтобы объяснить, что делает код, а скорее объяснить, почему он это делает. И в таких ситуациях часто рефакторингу доводят дело до конца, не нуждаясь в комментариях (что звучит как точка Яна).
RJFalconer
4

В этом конкретном случае @Mattieu M. имеет правильное решение.

В более общем случае, когда нет подобного преобразования, вы должны спросить себя: есть ли шанс, что будущий программист может испортить это?

Ответ обычно да. Что означает, да, вы должны добавить вызов. Может быть, какая-то будущая версия фреймворка начинается с выключения всех представлений вместо включения.

Стиг Хеммер
источник