Чи викидаєте аргументексцепцію або аргументовану думку про приватні методи?


20

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

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

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

Відповіді:


22

Зазвичай для приватних методів ви не викидаєте винятків, оскільки, як ви це писали, розробник повинен знати, як і звідки він викликає метод. Таким чином, змінні, передані як параметри приватному методу, повинні перевірятися поза методом, тобто перед викликом його. Кидання "InvalidArgumentException" та інших таких винятків вважається хорошою практикою для публічних методів (ви пишете "API" чи ні).

У тих випадках, коли ви хочете викинути "InvalidArgumentException", варто згадати, що Assertв Spring API для Java існує клас з версії 1.1.2. Мені було дуже корисно - принаймні, мені - писати менше коду для здійснення перевірок.

Однак ви можете використовувати "твердження" для перевірки параметрів у приватних методах. Це одна з їх справжніх цілей. Вони більше причин використовувати їх, перегляньте наступне посилання, яке також ретельно пояснює, коли слід використовувати твердження та коли використовувати виключення. Затвердження не повинні включатися у виробничий код, і компілятор видаляє їх за замовчуванням. Отже, це те, що ви шукаєте: допомога розробникам, невидима для користувачів. У Java вам потрібно використовувати спеціальний прапор ("-ea"), щоб сказати компілятору для включення тверджень. Ви можете вважати їх "друкуючими" друзями.

Ось як використовувати твердження в:


1
Apache Commons також має клас Validate, який функціонує аналогічно класу Spring's Assert
Rosa Richter

@cantido так, і я також додам, що клас "Передумови" в Guava Google, який працює так само. Дякую за інформацію :-)
Джалайн

2

Як і все, що залежить ...

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

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


2

Я усвідомлюю, що, хоча питання не має мовної позначки, воно, мабуть, неявно говорить про "мови кави". Але просто задля повноти я хотів би зазначити дещо розбіжний очевидний консенсус у світі C ++.

Існує три речі, які зазвичай цікавлять програмістів на C ++:

  • Чи буде вона мати нульові накладні витрати в оптимізованих складах? (Тобто чи можна його "скласти"?)
  • Чи можу я скористатися нею, щоб потрапити у відладчик прямо в точці, де виявлена ​​помилка?
  • Чи можу я використовувати його для повідомлення про проблеми із оголошених функцій noexcept?

Раніше я підходив до першої проблеми, написавши подібний код

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

де CHECK_ARGSзнаходиться #defined до постійна часу компіляції тому компілятор може повністю усунути всі аргумент коди перевірки в оптимізованої збірці. (Я не кажу, що компіляція виписок - це взагалі гарна річ, але я вважаю, що користувач повинен мати можливість їх складати.)

Мені все одно подобається у цьому рішенні, що код перевірки аргументів добре видно, згрупований у if. Однак друге і третє питання цим не вирішуються. Тому я знову більше схиляюся до використання assertмакросу для перевірки аргументів.

Стандарти кодування Boost погоджуються з цим:

Що з помилками програміста?

Як розробник, якщо я порушив попередню умову бібліотеки, яку я використовую, я не хочу відмовляти стек. Що я хочу, це основний дамп або його еквівалент - спосіб перевірити стан програми в точній точці, де була виявлена ​​проблема. Це зазвичай означає assert()або щось подібне.

На CppCon'14 під назвою Оборонне програмування зроблено право ( частина 1 , частина 2 ) була дуже цікава розмова Джона Лакоса . У першій частині своєї бесіди він обговорює теорію договорів та невизначену поведінку. У другій частині він подає те, що вважаю дуже хорошою пропозицією щодо систематичної перевірки аргументів. По суті, він пропонує макроствердження, які дозволяють користувачеві вибирати, яку частину бюджету (з точки зору використання процесора) вона готова пожертвувати бібліотеці для перевірки аргументів і змушує бібліотеку розумно використовувати цей бюджет. Крім того, користувач також може встановити глобальну функцію обробки помилок, яка буде викликана у випадку виявлення порушеного договору.

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


1

Розглянемо таку структуру:

  1. Внутрішня логіка: Ця функція передбачає викликати правильні параметри і для цього використовує твердження для перевірки передумов, постумов та інваріантів для перевірки вашої внутрішньої логіки.

  2. Інтерфейс обгортка: Ця функція обертає внутрішню функцію і використовує InvalidArgumentExceptions для обробки помилкових значень і сказати користувачеві , щоб виправити свої входи: Assert(x).hasLength(4);, Assume(y).isAlphanumeric();, Assert(z).isZipCode();, Assume(mailAdress).matchesRegex(regex_MailAdress);, Reject(x).ifEmpty();і т.д.

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

  4. Обгортка інтерфейсу командного рядка: ця функція перекриває внутрішню функцію і знову запитує останній ввід.

Вам слід використовувати як твердження, так і винятки - в різних методах для різних завдань. Вам слід відокремити внутрішню логіку від перевірки параметрів. Порівняйте його з розділенням Модель, Вид, Контролер.


0

Є кращі способи уникнути недійсної перевірки посилання: використовувати контракт з кодом або рамку AOP, щоб зробити перевірку за вас. Google "c # код контракту" або "postsharp".


Я думаю, моє питання пошириться і на кодові контракти. Чи є необхідність перевірити передумови методу в приватному методі (наприклад, для подальшої перевірки чи для того, щоб заважати вам стріляти в ногу)?
Містер Муз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.