Лучше Show () + Hide () или SetVisible (bool видимый)?

59

Что лучше и почему? (С точки зрения дизайна интерфейса):

а) иметь два Show()и Hide()функции

б) иметь одну SetVisible(bool visible)функцию

РЕДАКТИРОВАТЬ: Например, некоторые объекты имеют состояние видимости, и эта функция используется для его изменения.

в) иметь все три Show(), Hide(), SetVisible(bool visible)функции

user3123061
источник
4
В каком контексте? Вообще это не имеет значения
Авив Кон
6
Почему бы не сделать их всех публичными? Есть случаи, когда вы знаете, что они всегда будут показаны или скрыты, и есть случаи, когда вы хотели бы условно показать или скрыть.
pllee
@pllee: Это, наверное, очень хорошая мысль.
user3123061
4
В Java это будет установлено Visible, скрыть и показать без начальной заглавной буквы.
Пьер Арло

Ответы:

81

Я предпочитаю SetVisible(bool visible), потому что это позволяет мне писать код клиента так:

SetVisible(DetermineIfItShouldBeVisible());

вместо того, чтобы писать

if (DetermineIfItShouldBeVisible()) {
    Show();
} else {
    Hide();
}

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

void ButtonWithALabel::SetVisible(bool visible) {
    myButton.SetVisible(visible);
    myLabel.SetVisible(visible);
}
Джош Келли
источник
25
Эквивалентно, вы также можете сделать Visible свойством, если ваш язык поддерживает его. MyObject.Visible = false;мне кажется еще более интуитивным, чемMyObject.SetVisible(false);
Брайан
9
@ Брайан Для меня это менее читабельно и отлаживаемо, потому что скрывает поведение программы для моих глаз - вызов базового метода - но это уже другая история. Java не поддерживает этот синтаксис, в любом случае, это вопрос предпочтений и тренировки глаз.
Игнис
10
SetVisible()не предлагает (для меня), что вы на самом деле что-то показывает. Это больше похоже на то, что вы устанавливаете свойство видимости объекта, возможно, оставляя его на усмотрение соответствующего метода Refresh()или Redisplay()метода, чтобы проверить значение этого свойства, чтобы определить, должен ли объект отображаться или скрываться.
TMN
1
К сожалению, Java не поддерживает свойства, как в C #, только те методы получения и установки, которые вы видите выше.
theGreenCabbage
1
@ TMN: Я ожидал бы, что в отсутствие других факторов, препятствующих видимости (порядок Z, видимость родителей, местоположение и т. Д.), setVisible(true)Будет запущен процесс, при котором объект будет прорисован, когда система будет в следующий раз бездействующей, если не раньше. Я ожидаю, что это refreshможет быть полезно для ускорения отображения объекта, но что объект в конечном итоге будет нарисован независимо (если, например, его видимость не была установлена ​​до falseтого, как это произошло).
суперкат
35

Я не согласен со всеми плакатами, предлагающими несколько функций для выполнения одной и той же вещи - это хорошо. Хотя три функции вместо одного может показаться не так много наворотов, помните , что ваш класс, скорее всего, в конечном итоге с большим количеством таких функций (например setEnabled, enable, disable) и , таким образом , этот подход будет в конечном итоге с гораздо большим интерфейсом класса. Более того, вполне вероятно, что в результате вы получите кучу схожих по звучанию функций / свойств / чего угодно в вашем классе, и умножение функций еще больше затеняет, какой из них идет с чем.

В языках, которые поддерживают свойства, они должны быть предпочтительнее, но, поскольку ни Java, ни C ++ не поддерживают, я думаю, это спорный вопрос.

Я думаю, что setVisible()следует отдавать предпочтение по этим причинам:

  1. Сразу видно, что такое обратная функция. На обратный setVisible(false)вызов вы звоните, setVisible(true)тогда как противоположность hide()легко может быть reveal().
  2. Программно проще всякий раз, когда вы определяете, какое состояние должно быть в коде, т.е. вы можете вызывать, setVisible(wantToSee)а не использовать ifоператор.
  3. Если у вас есть несколько похожих функций, setX()формат обобщается, поэтому вы можете иметь набор согласованных функций, в то время как подход с использованием глаголов порождает множество функций, которые может быть трудно найти, если вы не знаете, что ищете. Согласованность API-интерфейсов значительно облегчает их изучение и запоминание.
Джек Эйдли
источник
3
C ++ не имеет свойств, но у него есть свободные функции, поэтому вы можете расширить интерфейс класса, не добавляя новые функции-члены, то есть с более низкой степенью связи.
Френел
Qt часто предоставляет все три для удобства, так что hide () и show () могут быть напрямую связаны с другими событиями, используя систему сигнал / слот. Это действительно ограничение системы слотов, хотя - если бы она использовала что-то более похожее на boost :: functions, аргумент true / false мог бы быть привязан в точке установки обратного вызова.
1
«В языках, которые поддерживают свойства, они должны быть предпочтительнее, но, поскольку ни Java, ни C ++ не поддерживают, я думаю, это спорный вопрос». не обязательно. Предпочтение геттерам / сеттерам? Да. Но set_visible на самом деле не является сеттером.
Майлз Рут
19

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

  • Причины выбрать setVisible(bool)
    • Это просто простой переворот, или ваш объект в основном удерживает состояние
    • Ваш объект будет проводить большую часть своего времени в рамках CRUD
    • Существует много легко разделяемого кода между показом и скрытием
  • Причины выбрать show()иhide()
    • Существуют важные побочные эффекты или большое количество выполняемой логики, например, когда объект должен проверять все свои контейнеры на предмет их состояния видимости или запускает анимацию перехода.
    • Является ли это частью модели предметной области, где важно выразить намерение

Итак, теперь, когда вы закодировали его «золотой стандарт», вам нужно выяснить, стоит ли добавлять тонкие удобные методы в другом стиле, чтобы облегчить жизнь тому, кто будет использовать ваш объект.

  • Удобство setVisible(bool)
    • Позволяет избежать операторов if, которые имеют тривиальные условия и влияют только на видимость (напр. setVisible(a==b))
    • Может быть подключен к определенным средам получения / установки, если вы ожидаете, что это произойдет
  • Удобство show()иhide()
    • Полезно в языке с первоклассными функциями и обратными вызовами (напр. onSuccess(widget.show))
    • Намного легче читать с трассировкой стека и профилированием производительности, так как вы можете быстро увидеть, что программа пыталась сделать

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

Darien
источник
11

Я бы сказал "все три".

Show()и, Hide()как правило, легче впасть, чем SetVisible(true)и SetVisible(false). Однако, когда вы хотите установить видимость логически, лучше иметь метод, который принимает, boolа не создает ifвокруг него bool.

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

void Show() {
    foo.Show();
    bar.Show();
}

void Hide() {
    foo.Hide();
    bar.Hide();
}

void SetVisible(bool visible) {
    if (visible) {
        Show();
    } else {
        Hide();
    }
}

В качестве альтернативы, если вещи, которые вы упаковываете, имеют более SetVisible-рочный API:

void Show() {
    SetVisible(true);
}

void Hide() {
    SetVisible(false);
}

void SetVisible(bool visible) {
    foo.SetVisible(visible);
    bar.SetVisible(visible);
}
Гарри Шутлер
источник
40
Microsoft использует этот подход для запуска и остановки System.Windows.Forms.Timer. Лично я считаю, что это сбивает с толку. Когда я вижу и то, Showи другое SetVisible, я склоняюсь к мысли, есть ли какое-то важное различие между этими двумя функциями.
Брайан
1
Вы можете легко документировать их, чтобы устранить эту путаницу. Я не сделал, так как это был простой пример.
Гарри Шутлер,
20
Так что теперь мне нужно потратить X лишних минут на чтение документации, прежде чем я буду чувствовать себя комфортно, используя класс? Или, в качестве альтернативы, мне нужно потратить X лишних минут на то, чтобы запутаться (или внести ошибки)? Конечно, X довольно маленький для такого рода вещей, но это определенно не ноль. Предлагая все 3 варианта, вы предлагаете в три раза больше функций, чем необходимо, что означает, что вы тратите больше рабочей документации, а я трачу больше времени на изучение того, как пользоваться классом. Кроме того, он представляет еще один способ для разных разработчиков быть непоследовательным при использовании вашего класса.
Брайан
5
Это явное нарушение принципа разделения интерфейса, одного из принципов SOLID. Еще одно мнение против вашего подхода - мнение Ярослава Тулаха, дизайнера NetBeans, который много раз настаивал на том, чтобы в своей книге «Практический API-дизайн» предлагался только один способ сделать что-то в рамках API.
AlfredoCasado
@AlfredoCasado Я согласен. Что если SetVisible был защищен, хотя? Вы можете получить к нему доступ из подкласса, но вызов данного объекта с таким интерфейсом (например, API) должен быть Hide / Show.
Пьер Арло
5

Я предпочитаю show () и hide (), фактически каждый метод, который получает один логический тип, может быть изменен на два метода, которые лучше выражают намерение API. Например, Роберт Мартин в чистом коде рекомендует отдавать предпочтение методам без аргументов по сравнению с методами с одним аргументом.

Другим важным аргументом для меня является удобочитаемость, на мой взгляд, хороший код можно читать как прозу, его действительно странную прозу, например, «main_window setVisible false» вместо «main_window hide», вы пишете или говорите так обычно? построение языка в программном обеспечении, когда вполне возможно использовать более естественный язык?

AlfredoCasado
источник
1
Разве ассемблерной прозы недостаточно?
Александр
Я ожидаю, что последовательность it.setVisible(false); it.setVisible(true);не должна влиять на видимость родительского элемента управления и не должна влиять на Z-порядок или местоположение элемента управления. В отличие от hide(); show(); вполне может заставить родителя элемента управления быть видимым, переместить его над другими элементами управления и ограничить его положение в каком-либо месте, которое можно увидеть. В некоторых случаях полезно иметь возможность убедиться, что что-то действительно видно (как в случае с вышеупомянутым show(), но в других случаях полезно изменить флаг видимости, не меняя ничего другого.
Суперкат
В объектно-ориентированном API нет «флагов», ОО - это обмен сообщениями, он говорит другим объектам о выполнении какой-либо задачи, а не об изменении «флагов», которые являются состоянием объекта. Вы делаете много предположений о контроле, родителях, z-упорядочении и вещах, которые ВЫ ожидаете, основываясь, вероятно, на своем предыдущем опыте работы с другими API. Это очень плохая идея - создавать API на основе личных чувств и предположений о домене.
АльфредоКасадо
5

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

Дело 1:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  customerPanel.setVisible(customer.isCustomerEnabled());
}

Случай 2:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  //always show customer panel
  customerPanel.setVisible(true);
}

В первом случае ясно, что делает функция setVisible, но если вы хотите прочитать ее, вы скажете:

установите панель клиента видимой, если клиент включен, или установите ее скрытой, если клиент отключен.

Хотя более информативно сказать:

  • проверить статус клиента:
    • если клиент включен, то показать панель клиента
    • в противном случае скрыть это

который изменит функцию «Случай 1» на следующее:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  if(customer.isCustomerEnabled()){
    customerPanel.Show();
  }
  else{
    customerPanel.Hide();
  }
}

он производит больше кода, но более читабелен.

Во втором случае есть очевидный недостаток: вы уже знаете, что хотите показать панель, так почему бы не использовать функцию «Показать»?

Я не говорю, что использование «setVisible» является абсолютно неправильным, но это сбивает с толку, когда вы пытаетесь прочитать код, не написанный вами с течением времени, и это не соответствует правилу «Функция должна выполнять только одну операцию».

OKAN
источник
Я бы сказал: show customer panel iff the user/customer is enabled. Я согласен с тем, что может быть множество более сложных условий, которые не так легко прочитать, как ваш пример, однако в этих случаях я бы разбил эти условия на разные строки.
ComFreek
5

Я полагаю, что Hide()/ Show()альтернатива привлекательна, потому что легче понять, что происходит, чем когда с ней SetVisible(true), хотя наличие единственной функции предпочтительнее, потому что она избегает множества условий.

Если это так, то я предлагаю использовать перечисление в качестве входных данных для SetVisible, так что вы получите либо SetVisible(Visibility.Visible)или SetVisible(Visibility.Hidden). У вас есть одна функция, вы можете мгновенно прочитать, какие действия предпринимаются.

Используя соглашения об именах Java, вы могли бы иметь setVisible(Visibility.VISIBLE)или setVisible(Visibility.HIDDEN).

Гейб
источник
3

Я согласен с ответом Дариена, но хотел добавить точку зрения с точки зрения программистов на C #.

Когда я вижу код, который говорит «setXXX», я читаю это, чтобы сказать, что он устанавливает значение для чего-либо, я не ожидаю, что это будет иметь побочные эффекты в этом, кроме установки этого значения, и я ожидаю, что это будет идемпотентным (т.е. я могу продолжать устанавливать его с тем же значением, и это нормально). Это скорее как доступ к полю. Как правило, я бы также ожидал увидеть метод getXXX вместе с setXXX.

Я не знаю, ожидаете ли вы этого в Java и C ++, но это то, что я ожидал бы в C #, хотя в C # есть сокращение для этого, называемое Properties. И вот несколько хороших советов о том, как использовать свойства ( http://msdn.microsoft.com/en-us/library/ms182181.aspx ).

Учитывая это представление, интерфейс, который я бы выбрал, зависит исключительно от наличия побочных эффектов (кроме изменения значения этого поля):

Если выполнение действия имеет побочные эффекты, например, оно показывает диалоговое окно, тогда я бы выбрал «Показать ()» и «Скрыть ()».

Если у него нет побочных эффектов, скажем, я устанавливаю видимость «виджета», а что-то еще отображает этот виджет в зависимости от его состояния, тогда я бы использовал setVisibility или setIsVisible. (Я бы не назвал это SetVisible).

В C # (не уверен в Java) довольно распространено использование шаблона наблюдателя, в котором инфраструктура пользовательского интерфейса будет прослушивать изменения объектов и автоматически повторно отображать пользовательский интерфейс при изменении свойства, такого как Visibility. Это означает, что установка значения путем вызова setIsVisible выглядит так, как будто у него есть побочные эффекты, но в моем определении это не так. Контракт виджета выполняется путем установки значения его поля, представляющего «IsVisible».

Другими словами, я могу переключать видимость метки в форме перед ее отображением. Т.е. label.getIsVisible == true, но форма не отображается.

Я не могу вызывать Hide (), когда форма не отображается.

Дэниел Джеймс Брайерс
источник
1
Ваше описание getXXX()и setXXX()методы как способ получить доступ к полю без побочных эффектов звучит как Java, а не как C #. Это способ, которым вы должны сделать это в Java, потому что у него нет свойств. Если бы я видел такой код в C #, я бы предположил, что он написан Java-разработчиком, который еще не узнал о свойствах в C #.
gilly3
+1 за SetVisibility.
Акалтар
@ gilly3 - Да, конечно. И "Свойства" не существуют в CLR, C # преобразуется в вызовы методов get_XXX и set_YYY в IL. Моя точка зрения такова: в контексте вопроса, если вы видели setXXX, getXXX в Java, вы ожидаете, что он будет работать с той же семантикой, что и свойства в C #. Если это так, то я полагаю, что те же рекомендации для свойств в C # применимы к парам setXXX и getXXX в Java. Я согласен с рекомендациями, на которые я ссылаюсь в посте, и поэтому я защищаю те же рекомендации для использования в этом сценарии в Java при определении интерфейса.
Даниэль Джеймс Брайерс
1
Это может помочь уточнить, что когда вы имеете в виду «побочные эффекты», вы имеете в виду «помимо тех, которые связаны с тем, чтобы быть« наблюдаемой »вещью». Правило, которое я одобряю, состоит в том, чтобы сказать, что если у getXXвызова есть соответствующий setXXметод, то он setYYне должен влиять на него, но это может повлиять на getZZвызов, у которого нет setZZметода.
суперкат
2

Я бы предложил немного измененный интерфейс:

Show();
Hide();
ToggleVisible();
ToggleVisible(bool visible);

Лучшие имена

Эти имена методов помогают разработчику решить, какой метод использовать, основываясь на том, что необходимо сделать. Принимая во внимание, SetVisible(bool visible)что разработчик может сбить с толку, поскольку он передает то же семантическое значение, что Show()и Hide(), Toggle()подразумевает существование условия, определяющего действие. Таким образом, становится понятным для разработчика, когда использовать каждый метод.

Уменьшенная избыточность кода

Преимущество наличия нескольких методов в вашем интерфейсе состоит в том, что это упрощает вызывающий код. Вы могли бы просто выставить Show()и Hide(), но:

  • Вам, вероятно, потребуется какой-то SetVisible()приватный метод, чтобы выполнить реальную работу за кулисами (или написать избыточный код для Show()и Hide()).
  • Вызывающий код может иметь много избыточных блоков if / else только для того, чтобы выбрать, какой метод использовать. Это раздувает код по моему мнению.
  • Если бы я был потребителем, я бы просто написал свою собственную функцию-обертку, которая делает то, что SetVisible()(или Toggle()) уже делает, чтобы избежать раздувания кода (я ненавижу избыточный код). Таким образом, дублируется метод, который, вероятно, уже существует как частный метод в реализации.
gilly3
источник
1
Дублирование метода звучит разумно, хотя я бы сам этого не делал. С другой стороны, я не согласен с тем, что toggleVisible (bool) интуитивно понятен. Для меня это означает, что он должен переключаться, если передано в bool верно, что было бы довольно странно, но я видел незнакомца. Это не предполагает, что это действительно скрытая функция set.
Патрик М
0

Я бы предложил использовать, SetVisible(bool)если таковые имеются, только если переключение видимости дважды (показать и повторно скрыть, или скрыть и повторно показать) оставило бы вещи по существу в том же состоянии, что и до выполнения операции (это хорошо, если показывать и повторно скрывать что-то или наоборот оставляет объекты нуждающимися в перерисовке, при условии, что это может произойти «автоматически»). Если сокрытие и показ объекта не будет иметь никакого эффекта, кроме изменения одного бита состояния, тогда для внешнего кода будет иметь смысл иметь некоторые методы, которые принимают параметр видимости, и написание такого кода будет облегчено SetVisible.

Если скрытие и повторное отображение объекта может иметь побочные эффекты, такие как изменение порядка Z, такие действия, скорее всего, следует выполнять отдельными методами. В таких случаях полезность внешних методов, которые принимают параметр «видимости», будет ограничена, и поэтому будет мало преимуществ для их облегчения. Кроме того, SetVisibleметод (ошибочно) предполагает, что изменения видимости объектов могут быть выполнены без побочных эффектов.

Supercat
источник