Як назвати метод, який виконує завдання і повертає булевий статус як статус?


33

Якщо є метод

bool DoStuff() {
    try {
        // doing stuff...
        return true;
    }
    catch (SomeSpecificException ex) {
        return false;
    }
}

чи варто його швидше називати IsStuffDone()?

Обидва імені може бути неправильно інтерпретовано користувачем: Якщо ім'я, DoStuff()чому воно повертає булеве? Якщо назва - IsStuffDone()невідомо, чи метод виконує завдання чи лише перевіряє його результат.

Чи існує умова для цього випадку? Або альтернативний підхід, оскільки цей вважається недосконалим? Наприклад, у мовах, які мають вихідні параметри, такі як C #, булева змінна статусу може бути передана методу як одна, і тип повернення методу був би void.

EDIT: У моїй конкретній проблемі обробка виключень не може бути безпосередньо делегована абоненту, оскільки метод є частиною реалізації інтерфейсу. Отже, абоненту не може бути доручено працювати з усіма винятками різних реалізацій. З тими винятками він не знайомий. Однак, абонент може вирішувати спеціальний виняток, як StuffHasNotBeenDoneForSomeReasonExceptionце було запропоновано у відповіді та коментарі npinti .


2
Це залежить від використання функції та того, що робиться. Якщо необхідно, щоб матеріал був виконаний правильно, я вважаю такий підхід недосконалим, оскільки користувач функції може пропустити булевий прапор, а також не вистачає інформації, що надається виключенням.
Бенні

7
Більшу частину часу я б назвав це "зламаним", оскільки повернення booleanзамість обгортання чи передавання винятку майже завжди неправильне.
maaartinus

2
Такий обробник винятків рідко є доброю ідеєю. Ловіть лише конкретні винятки, яких ви очікуєте, не всі. І по можливості уникайте його кидати в першу чергу, позбавляючи від необхідності ловити його.
CodesInChaos

2
Гм ... BadlyDesignedMethodInSeriousNeedOfRefactoring? І щоб відповісти на ваше запитання про винятки - я або дозволю абоненту обробляти їх, або спіймати їх, а потім викиньте спеціальний виняток, що означає "цей метод не робить своєї справи". Діліться та насолоджуйтесь.
Боб Джарвіс - Відновіть Моніку

5
Для всіх тих, хто каже: просто киньте (або відпустіть) виняток, ви робите необґрунтовані припущення щодо використання цього коду. Один з можливих сценаріїв полягає в тому, що існує проблема, яку необхідно вирішити, використовуючи різні евристичні методи вирішення, які вирішують все більші підкласи проблеми за будь-якої більшої вартості; було б сенс написати щось подібне if (FirstMethodSucceeds(problem) or SecondMethodSucceeds(problem) or ...) Hurray(); else UniversalSolve(problem);. Зробити те саме з (звичайними?) Винятками було б марно складніше.
Марк ван Левен

Відповіді:


68

У .NET у вас часто є пари методів, коли один з них може кинути виняток ( DoStuff), а інший повертає булевий статус і, при успішному виконанні, фактичний результат за допомогою параметра out ( TryDoStuff).

(Майкрософт називає це "Спробом розбору візерунка" , оскільки, мабуть, найвизначнішим прикладом для нього є TryParseметоди різних примітивних типів.)

Якщо Tryу вашій мові префікс рідкісний, ви, ймовірно, не повинні його використовувати.


3
+1 Ось як я бачив подібне, що робилося в інших місцях. if (TryDoStuff()) print("Did stuff"); else print("Could not do stuff");на мою думку, це досить стандартна та інтуїтивна ідіома.
Карл Ніколл

12
Слід зазначити, що TryDoStuffметоди вважаються невдалими та не мають побічного ефекту, коли вони повертаються помилково.
Триліан

FYI, є також Removeметоди, наприклад, у .NET Framework, які видалять елемент із структури даних (наприклад Dictionary) та повертають a bool. Споживач API може вирішити його споживати або ігнорувати. Однак помилки повідомляються як винятки.
Омер Ікбал,

18

Що робити, якщо ви просто кинули виняток з викликового коду?

Таким чином ви делегуєте обробку винятків тому, хто коли-небудь використовує ваш код. Що робити, якщо в майбутньому ви хочете зробити наступне:

  • Якщо жодних винятків не буде, киньте дії А
  • Якщо (наприклад) a FileNotFoundExceptionкинуто, вживайте дії B
  • Якщо викинуто будь-який інший виняток, вживати заходів C

Якщо ви відкинете виняток, зазначена вище зміна просто тягне за собою додавання додаткового catchблоку. Якщо ви залишите його таким, яким він є, вам знадобиться змінити метод і місце, з якого називається метод, який, залежно від складності проекту, може бути в декількох місцях.


1
Що робити, якщо виняток такого роду, який не може бути делегований і з ним слід вирішувати внутрішньо?
Лімбо-заслання

2
@LimboExile: Я думаю, що ви все-таки могли би вирішити це з внутрішньої точки, а потім, можливо, киньте ще один виняток, можливо ваш власний. Це ілюструє те, що щось, чого не мало статися, мало місце, але в той же час ви не викривали те, що насправді відбувається під капотом, і я припускаю, що саме тому ви хочете мати справу з винятком всередині країни.
npinti

6
Мабуть, варто пам’ятати, що кидати виняток слід виключно . Якщо це звичайно або нормально для DoStuffвідмови, кидання винятку для випадку відмови було б подібним до контролю потоку програми за винятком, що погано. Винятки мають також властиву собівартість. Якщо DoStuffпомилка є нечастою справою через помилку, то винятки, безумовно, є способом пройти, як пропонує @npinti.
Карл Ніколл

1
@KarlNicoll Чи є щось "виняткове" - це абсолютно суб'єктивно. Основними критеріями повинні бути, чи хочете ви, щоб програма вийшла з ладу, якщо ніхто нічого не робив про помилку, і чи хочете ви, щоб можливість помилки була присутня у типі функції. Крім того, не факт, що винятки дорогі; це залежить від мови та того, як ви їх кидаєте. Винятки дешеві в Python, і якщо ви знімете інформацію про сліди стека, вони можуть бути дешевими і на Яві. Навіть якщо була вартість продуктивності, заздалегідь хвилюватися з цього приводу, поки ви не профілізуєтесь.
Doval

1
@Doval - Я погоджуюсь, що це суб'єктивно, тому ОП не слід повністю відкидати відповідь npinti, оскільки це може бути найкращим способом дій. Моя думка полягала в тому, що кидання винятків - не завжди найкращий шлях. Існує маса випадків, коли збій не виправдовує викидання виключення та потенційну помилку програми. Наприклад, якщо DoStuff()метод ОП очищається після того, як внутрішній код видаляє виняток, а Пост-умови методу все ще є правильними, зворотний код може бути кращим варіантом, оскільки помилка була оброблена.
Карл Ніколл

7

DoStuff() достатньо, і повертане значення функції повинно бути задокументовано, і вам не потрібно згадувати це у назві функції, шукаючи багато доступних API:

PHP

// this method update and return the number affected rows 
// called update instead of updateAndGetAffectedCount
$affected = $query->update(/* values */);

C-Різкий

// Remove item from the List
// returns true if item is successfully removed; otherwise, false.
public bool Remove( T item )

6

У Java API колекції визначає метод додавання, який повертає булева. Це в основному повертає, чи змінив колекцію додаток. Так що для a List, як правило, повертається true, оскільки елемент був доданий, тоді як для a Setвін може повернути помилковий, якщо елемент вже був, оскільки Sets дозволяють отримати кожен унікальний елемент не більше одного разу.

Це означає, що якщо ви додасте елемент, який колекція не дозволена, наприклад, нульове значення, додавання буде кидати, NullPointerExceptionа не повертати помилкове.

Якщо ви застосовуєте ту саму логіку до свого випадку, навіщо вам повертати булеве? Якщо потрібно приховати виняток, не робіть цього. Просто киньте виняток. Таким чином ви зможете побачити, що пішло не так. Якщо вам потрібен булевий, оскільки це, можливо, не було зроблено, з іншої причини, ніж виняток, назвіть метод DoStuff(), оскільки це відображає поведінку. Це робить речі.


1

Можливо, з різних причин виняток, виняток, нормальні умови, тому використовуйте це:

boolean doStuff() - returns true when successful

Важливо - задокументувати, що означає булева.


1

Зазвичай у мене є методи повернення OperationResult(або OperationResult<T>) та встановлення IsSuccessвластивості на OperationResultналежному рівні. Якщо метод "звичайний" недійсний, тоді повертається OperationResult, якщо метод "звичайний" повертає об'єкт, тоді повертається OperationResult<T>та встановлює Itemвластивість на OperationResultвідповідний спосіб. Я б також запропонував використовувати OperationResultтакі методи як .Failed(string reason)і .Succeeded(T item). OperationResultшвидко стає звичним типом у ваших системах, і розробники знайомляться з цим.


0

Це дійсно залежить від мови, якою ви користуєтесь. Як і для деяких мов, існують конвенції та протоколи, які насправді не існують у багатьох мовах або взагалі немає.

Наприклад, у мові Objective-C та iOS / Mac OS X SDK імена зазвичай йдуть уздовж рядків:

- (returndatatype) viewDidLoad {
- (returndatatype) isVisible {
- (returndatatype) appendMessage:datatype variablename with:datatype variablename {

Як бачите, існує метод, який називається viewDidLoad. Я вважаю за краще використовувати цей тип імен, коли я роблю власні програми. Це можна використати для перевірки, чи мало щось статися, як ви сказали. Я вважаю, що ви занадто глибоко розмірковуєте над тим, що саме ви називаєте свої методи. Більшість методів повертає статус того, що вони роблять незалежно, наприклад:

У PHP, mysql_connect () поверне помилкове, якщо з'єднання не вдасться. Це не говорить, що це буде, але це так, але в документації написано, що це робиться, тому його не можна неправильно трактувати програмісту.


Так, але viewDidLoad - це більше повідомлення про зворотний виклик. Користувачі не називають його для завантаження перегляду. Швидше, він викликається після завантаження перегляду. Так само: isVisible не встановлює видимість, скоріше просто повертає те, що є поточним значенням. Це нічого не робить .
lilbyrdie

0

Я хотів би запропонувати використовувати префікс "Спробувати". Це добре відома закономірність ситуацій, коли метод може досягти успіху чи ні. Цей шаблон іменування використовувався Microsoft в .NET Framework (наприклад, TryParseInt).

Але, можливо, мова йде не про називання. Йдеться про те, як ви проектуєте параметри вводу / виводу методу.

Моя ідея полягає в тому, що якщо метод має повернене значення, то метою виклику цього методу має бути отримання цього поверненого значення. Отже, вам слід уникати використання типу повернення для вказівки стану операції.

У C # я вважаю за краще використовувати параметр out. Використовуючи вихід, я маркую параметр як бічний параметр. Особливо те, що C # 6 підтримуватиме вбудовану змінну оголошення.

DoStuff(out var isStuffDone); // The out parameter name clearly states its purpose.
DoStuff(out var _); // I use _ for naming parameters that I am ignoring.

0

Я б вибрав ім'я, грунтуючись на основній ролі методу. Той факт, що цей метод повертає булеве значення, не містить префікса "Є". Будемо мати якийсь код Java, в якому досить широко використовується префікс 'Is'. Погляньте java.io.File.delete(). Він повертається boolean, але його не називають isFileDeleted(). Причина полягає в тому, що головна роль методу - видалення файлу. Хтось називає цей метод з наміром видалити файл.

Булева інформація є просто для того, щоб озвучити результат роботи. З іншого боку давайте подивимось java.util.Map.isEmpty(). Очевидно, ви викликаєте такий метод, щоб дізнатися, чи колекція порожня. Ви не хочете, щоб якісь речі були зроблені. Ви просто хочете з’ясувати, який зараз стан.

Тож особисто я б точно дотримувався DoStuff().

Це дещо дуже важливе питання для мене. Багато разів, коли я зберігаю застарілий код, я натрапляю на те, що я називаю особисто "методом брехні". Назва пропонує дію A, але тіло робить дію B. Найбільш химерний приклад використання методу геттера, що змінює дані в базі даних.

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