Ketika saya mencoba membuat antarmuka untuk program tertentu, saya biasanya berusaha menghindari pengecualian yang bergantung pada input yang tidak divalidasi.
Jadi yang sering terjadi adalah saya sudah memikirkan sepotong kode seperti ini (ini hanya contoh demi contoh, jangan pedulikan fungsi yang dijalankannya, contoh di Jawa):
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();
}
OK, jadi katakan itu evenSize
sebenarnya berasal dari input pengguna. Jadi saya tidak yakin itu adil. Tapi saya tidak ingin memanggil metode ini dengan kemungkinan pengecualian dilemparkan. Jadi saya membuat fungsi berikut:
public static boolean isEven(int evenSize) {
return evenSize % 2 == 0;
}
tapi sekarang saya punya dua pemeriksaan yang melakukan validasi input yang sama: ekspresi dalam if
pernyataan dan cek eksplisit dalam isEven
. Kode duplikat, tidak baik, jadi mari kita refactor:
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();
}
OK, itu menyelesaikannya, tapi sekarang kita masuk ke situasi berikut:
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)
sekarang kita sudah mendapatkan redundant check: kita sudah tahu bahwa nilainya genap, tetapi padToEvenWithIsEven
masih melakukan pemeriksaan parameter, yang akan selalu mengembalikan true, seperti yang kita sudah memanggil fungsi ini.
Sekarang isEven
tentu saja tidak menimbulkan masalah, tetapi jika pemeriksaan parameter lebih rumit maka ini mungkin menimbulkan biaya terlalu banyak. Selain itu, melakukan panggilan redundan sama sekali tidak terasa benar.
Terkadang kita dapat mengatasi ini dengan memperkenalkan "tipe yang divalidasi" atau dengan membuat fungsi di mana masalah ini tidak dapat terjadi:
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();
}
tetapi ini membutuhkan pemikiran yang cerdas dan refactor yang cukup besar.
Apakah ada (lebih) cara umum di mana kita dapat menghindari panggilan yang berlebihan isEven
dan melakukan pengecekan parameter ganda? Saya ingin solusi untuk tidak benar-benar memanggil padToEven
dengan parameter yang tidak valid, memicu pengecualian.
Tanpa pengecualian saya tidak bermaksud pemrograman bebas pengecualian, maksud saya bahwa input pengguna tidak memicu pengecualian oleh desain, sedangkan fungsi generik itu sendiri masih berisi pemeriksaan parameter (jika hanya untuk melindungi terhadap kesalahan pemrograman).
padToEvenWithIsEven
tidak melakukan validasi input pengguna. Ia melakukan pemeriksaan validitas pada inputnya untuk melindungi dirinya dari kesalahan pemrograman dalam kode panggilan. Seberapa luas validasi ini perlu tergantung pada analisis biaya / risiko di mana Anda meletakkan biaya cek terhadap risiko yang dilewati orang yang menulis kode panggilan dalam parameter yang salah.