Чи краще Show () + Hide () або SetVisible (bool видимий)?


59

Що краще і чому? (З точки зору дизайну інтерфейсу):

а) Мати дві Show()і Hide()функції

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

EDIT: Наприклад, деякий об’єкт має стан видимості, і ці функції використовуються для його зміни.

в) мати всі три Show(), Hide(), SetVisible(bool visible)функції


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
@Brian Для мене це менш читабельно і налагоджується, тому що він приховує програмну поведінку на мої очі - базовий виклик методу - але це вже інша історія. Java не підтримує цей синтаксис, все одно це питання уподобань та тренувань очей.
ignis

10
SetVisible()не підказує (мені), що ви насправді нічого не показуєте. Він читає більше, як ви встановлюєте властивість видимості об’єкта, можливо, залишаючи його відповідному Refresh()чи Redisplay()методу, щоб перевірити значення цього властивості, щоб визначити, чи слід об’єкт відображати чи приховувати.
TMN

1
На жаль, Java не підтримує такі властивості, як C #, а лише геттери та сетери, які ви бачите вище.
theGreenCabbage

1
@TMN: Я б очікував, що за відсутності інших факторів, що перешкоджають видимості (порядок Z, видимість батьків, розташування тощо), setVisible(true)приведе в дію процес, коли об’єкт витягується, коли система буде в черговому режимі, якщо не раніше. Я б очікував, що це refreshможе бути корисним для прискорення відображення об'єкта, але в кінцевому підсумку об'єкт вийде незалежно (якщо, наприклад, його видимість не була встановлена falseраніше, ніж це відбулося)
supercat

35

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

Мовам, які підтримують властивості, слід віддати перевагу цим, але оскільки ні Java, ні C ++ не роблять, я думаю, що це суперечка.

Думаю, setVisible()слід віддати перевагу з цих причин:

  1. Відразу очевидно, що таке обернена функція. Для зворотного setVisible(false)дзвінка ви телефонуєте, setVisible(true)тоді як протилежне hide()може бути легко reveal().
  2. Це програмно простіше, коли ви визначаєте, який стан він повинен приймати в коді, тобто ви можете зателефонувати, setVisible(wantToSee)а не використовувати ifоператор.
  3. Коли у вас є кілька подібних функцій, setX()формат узагальнюється, щоб ви могли мати набір послідовних функцій, тоді як багатослівний підхід породить безліч функцій, які важко знайти, якщо ви не знаєте, що шукаєте. Послідовність в API значно полегшує їх вивчення та запам'ятовування.

3
C ++ не має властивостей, але у нього є вільні функції, тому ви можете розширити інтерфейс класу без додавання нових функцій-членів, тобто з меншим ступенем зв'язку.
френель

Qt часто надає всі три як зручність, щоб сховати () і show () можна з'єднати безпосередньо з іншими подіями за допомогою системи сигналів / слотів. Це насправді обмеження системи слотів - якщо б вона використовувала щось більше, як boost :: функції, аргумент 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: Дізнайтеся, який із них є найважливішим, реалізуйте його, а потім запитайте себе, чи варто додати інший стиль як тонкі методи зручності.


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();
    }
}

Крім того, якщо речі, які ви збираєте, мають більш- SetVisibleAPI 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 досить невеликий для подібних речей, але це точно не нуль. Запропонувати всі 3 варіанти означає запропонувати втричі більше функцій, ніж потрібно, а це означає, що ви витрачаєте більше документування на роботу, і я витрачаю більше роботи на навчання класу. Крім того, він пропонує ще один спосіб, коли різні розробники можуть бути непослідовними при використанні вашого класу.
Брайан

5
Це явне порушення принципу сегрегації інтерфейсів, одного із принципів SOLID. Ще одна думка проти Вашого підходу - це думка Ярослава Тулаха, дизайнера мережевих бобів, який наполягає багато разів на тому, щоб у своїй практичній програмі API для книги лише один спосіб зробити одну справу в рамках API.
AlfredoCasado

@AlfredoCasado Я згоден. Що робити, якщо SetVisible був захищений ? Ви можете отримати доступ до нього з підкласу, але виклик певної сутності з цим інтерфейсом (наприклад, API) повинен бути Hide / Show.
П’єр Арло

5

Я вважаю за краще show () і hid ((), насправді кожен метод, що отримує один булевий, можна змінити двома методами. Наприклад, Роберт Мартін у чистому коді рекомендує віддати перевагу методам з нульовими аргументами перед методами з одним аргументом.

Ще один важливий аргумент для мене - читабельність, на мій погляд, хороший код можна читати як прозу, його дійсно дивна проза, щось на кшталт "main_window setVisible false" замість "main_window сховати", ви пишете чи говорите так, як зазвичай ?, навіщо використовувати це дивно побудова мови в програмних програмах, коли цілком можливо використовувати більш природну мову ?.


1
Чи недостатньо прози Асемблера?
Олександр

Я б очікував, що послідовність it.setVisible(false); it.setVisible(true);не повинна впливати на видимість батьків контролю, а також не повинна впливати на порядок Z або розташування управління. На відміну від цього hide(); show(); може цілком правдоподібно змусити батьків-контроль контролера бути помітним, перемістити його над іншими елементами управління та обмежити його положення де-небудь, яке можна побачити. В деяких випадках корисно мати засоби, щоб переконатися, що щось дійсно видно (як у вищезгаданому show(), але в інших випадках корисно змінити прапор видимості, не змінюючи нічого іншого.
supercat

В об’єктно-орієнтованому API немає "прапорів", OO - про обмін повідомленнями, його про те, щоб сказати іншому об'єкту, виконати якусь задачу, а не про зміну "прапорів", які є станом об'єкта. Ви робите багато припущень щодо контролю, батьків, замовлення z і того, що ви очікуєте, виходячи з вашого попереднього досвіду роботи з іншими API, дуже погана ідея розробити API на основі особистих почуттів та припущень щодо домену.
AlfredoCasado

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" абсолютно неправильно, але воно стає заплутаним, коли ви намагаєтеся прочитати код, не написаний вами з часом, і це не відповідає правилу "Функція повинна виконувати лише одну операцію".


Я б сказав: 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 == вірно, але форма не відображається.

Мені не годиться телефонувати 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методу.
supercat

2

Я б запропонував трохи змінити інтерфейс:

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

Кращі назви

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

Зменшення надмірності коду

Перевага від наявності декількох методів у вашому інтерфейсі полягає в тому, що це спрощує код виклику. Ви можете просто викрити Show()і Hide(), але:

  • Можливо, вам знадобиться якийсь SetVisible()приватний метод, щоб виконати справжню роботу за лаштунками (або написати зайвий код для Show()і Hide()).
  • Код виклику може мати багато зайвих, якщо / else блокує просто для вибору, який метод використовувати. Це роздуває код на мій погляд.
  • Якби я був споживачем, я, швидше за все, просто напишу власну функцію обгортки, яка робить те, що SetVisible()(або Toggle()) вже робить, щоб уникнути розмивання коду (ненавиджу зайвий код). Таким чином, дублювання методу, який, ймовірно, вже існує як приватний метод в реалізації.

1
Дублювання методу здається розумним, хоча я би цього не робив сам. З іншого боку, я не згоден, що toggleVisible (bool) інтуїтивно зрозумілий. Для мене це означає, що він повинен перемикатися, якщо передане в bool є правдивим, що було б досить дивно, але я бачив незнайоме. Не припускалося б, що це дійсно задана функція у маскуванні.
Патрік М

0

Я б запропонував використовувати, SetVisible(bool)якщо такий існує лише в тому випадку, якщо зміна видимості двічі (показати та повторно приховати, або заховати і повторно показати) залишила б речі по суті в тому ж стані, що і до операції (це добре, якщо показ і повторне приховування щось або навпаки залишає об’єкти, які потребують перемальовки, за умови, що можна очікувати, що вони відбудуться "автоматично"). Якщо приховування та показ об'єкта не матиме жодного ефекту, окрім зміни одного біту стану, тоді зовнішній код має сенс мати деякі методи, які приймають параметр видимості, і написання такого коду полегшиться SetVisible.

Якщо приховування та повторний показ об'єкта може мати такі побічні ефекти, як зміна порядку Z, такі дії, швидше за все, слід виконувати окремими методами. У таких випадках корисність зовнішніх методів, які приймають параметр "видимість", буде обмежена, і тому їх полегшення буде мало. Далі SetVisibleметод (помилково) підкаже, що зміни видимості об'єктів можуть бути здійснені без побічних ефектів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.