Wenn ich versuche, eine Schnittstelle für ein bestimmtes Programm zu erstellen, versuche ich im Allgemeinen, Ausnahmen zu vermeiden, die von nicht validierten Eingaben abhängen.
Was also oft passiert, ist, dass ich an einen solchen Code gedacht habe (dies ist nur ein Beispiel für ein Beispiel, egal welche Funktion er ausführt, Beispiel in 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();
}
OK, sagen wir also, dass dies evenSize
tatsächlich aus Benutzereingaben abgeleitet wird. Ich bin mir also nicht sicher, ob es gerade ist. Ich möchte diese Methode jedoch nicht mit der Möglichkeit aufrufen, dass eine Ausnahme ausgelöst wird. Also mache ich folgende Funktion:
public static boolean isEven(int evenSize) {
return evenSize % 2 == 0;
}
Jetzt habe ich zwei Überprüfungen, die dieselbe Eingabevalidierung durchführen: den Ausdruck in der if
Anweisung und das explizite Einchecken isEven
. Doppelter Code, nicht schön, also lasst uns umgestalten:
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, das hat es gelöst, aber jetzt kommen wir in die folgende Situation:
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)
Jetzt haben wir eine redundante Prüfung: Wir wissen bereits, dass der Wert gerade ist, führen aber padToEvenWithIsEven
dennoch die Parameterprüfung durch, die immer true zurückgibt, wie wir diese Funktion bereits aufgerufen haben.
Das ist isEven
natürlich kein Problem, aber wenn die Parameterprüfung umständlicher ist, kann dies zu hohe Kosten verursachen. Außerdem fühlt sich ein redundanter Anruf einfach nicht richtig an.
Manchmal können wir dies umgehen, indem wir einen "validierten Typ" einführen oder eine Funktion erstellen, bei der dieses Problem nicht auftreten kann:
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();
}
Dies erfordert jedoch ein kluges Denken und einen ziemlich großen Refaktor.
Gibt es eine (allgemeinere) Methode, mit der wir redundante Aufrufe isEven
und doppelte Parameterprüfungen vermeiden und durchführen können? Ich möchte, dass die Lösung nicht padToEven
mit einem ungültigen Parameter aufruft und die Ausnahme auslöst.
Ohne Ausnahmen meine ich keine ausnahmefreie Programmierung, ich meine, dass Benutzereingaben keine Ausnahme von Natur aus auslösen, während die generische Funktion selbst noch die Parameterprüfung enthält (wenn auch nur zum Schutz vor Programmierfehlern).
padToEvenWithIsEven
keine Überprüfung der Benutzereingaben durchgeführt wird. Es führt eine Gültigkeitsprüfung seiner Eingabe durch, um sich vor Programmierfehlern im aufrufenden Code zu schützen . Wie umfangreich diese Validierung sein muss, hängt von einer Kosten- / Risikoanalyse ab, bei der Sie die Kosten der Prüfung gegen das Risiko stellen, dass die Person, die den aufrufenden Code schreibt, den falschen Parameter übergibt.