Коли я намагаюся створити інтерфейс для певної програми, я, як правило, намагаюся уникати викидів, що залежать від неперевірених даних.
Тож часто трапляється так, що я придумав такий фрагмент коду (це лише приклад заради прикладу, не заперечуйте проти функції, яку він виконує, наприклад у Java):
public static String padToEvenOriginal(int evenSize, String string) {
if (evenSize % 2 == 1) {
throw new IllegalArgumentException("evenSize argument is not even");
}
if (string.length() >= evenSize) {
return string;
}
StringBuilder sb = new StringBuilder(evenSize);
sb.append(string);
for (int i = string.length(); i < evenSize; i++) {
sb.append(' ');
}
return sb.toString();
}
Добре, так що кажіть, що evenSize
насправді є результатом введення користувача. Тож я не впевнений, що це рівномірно. Але я не хочу називати цей метод з можливістю викидання виключення. Тому я виконую таку функцію:
public static boolean isEven(int evenSize) {
return evenSize % 2 == 0;
}
але тепер у мене є дві перевірки, які виконують однакову перевірку вводу: вираз у if
операторі та явна реєстрація isEven
. Дублікат коду, не приємно, тому давайте рефактор:
public static String padToEvenWithIsEven(int evenSize, String string) {
if (!isEven(evenSize)) { // to avoid duplicate code
throw new IllegalArgumentException("evenSize argument is not even");
}
if (string.length() >= evenSize) {
return string;
}
StringBuilder sb = new StringBuilder(evenSize);
sb.append(string);
for (int i = string.length(); i < evenSize; i++) {
sb.append(' ');
}
return sb.toString();
}
Гаразд, це вирішило, але зараз ми потрапляємо в таку ситуацію:
String test = "123";
int size;
do {
size = getSizeFromInput();
} while (!isEven(size)); // checks if it is even
String evenTest = padToEvenWithIsEven(size, test);
System.out.println(evenTest); // checks if it is even (redundant)
тепер у нас з’явилася зайва перевірка: ми вже знаємо, що значення є парним, але padToEvenWithIsEven
все ще виконується перевірка параметрів, яка завжди поверне справжнє значення, як ми вже називали цю функцію.
Зараз, isEven
звичайно, не виникає проблем, але якщо перевірка параметрів більш громіздка, це може спричинити занадто великі витрати. Крім того, виконувати надмірний дзвінок просто не відчуває себе правильно.
Іноді ми можемо обійти це, ввівши "перевірений тип" або створивши функцію, коли ця проблема не може виникнути:
public static String padToEvenSmarter(int numberOfBigrams, String string) {
int size = numberOfBigrams * 2;
if (string.length() >= size) {
return string;
}
StringBuilder sb = new StringBuilder(size);
sb.append(string);
for (int i = string.length(); i < size; i++) {
sb.append('x');
}
return sb.toString();
}
але для цього потрібне розумне мислення і досить великий рефактор.
Чи існує (більш) загальний спосіб, яким ми можемо уникнути зайвих викликів isEven
та перевірити подвійні параметри? Я хотів би, щоб рішення насправді не викликало padToEven
недійсний параметр, викликаючи виняток.
Не маючи на увазі винятків, я не маю на увазі програмування без винятку, я маю на увазі, що введення користувачем не викликає винятку по дизайну, тоді як сама загальна функція все ще містить перевірку параметрів (якщо тільки для захисту від помилок програмування).
padToEvenWithIsEven
не виконується перевірка введення користувача. Він здійснює перевірку валідності на своєму вході, щоб захистити себе від помилок програмування в коді виклику. Наскільки обширна ця перевірка повинна бути, залежить від аналізу вартості / ризику, коли ви ставите вартість перевірки проти ризику, коли особа, яка пише телефонний код, передає неправильний параметр.