2013-05-28 10 views
16

Etwas war schon immer neugierig gewesenVersuchen Sie/fangen Sie im Konstruktor - empfohlene Praxis? Ich

public class FileDataValidator { 

private String[] lineData; 

public FileDataValidator(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
    } 
    catch(InvalidFormatException e) 
    { 
     e.printStackTrace(); 
    } 

} 

//validation methods below all throwing InvalidFormatException 

ist nicht ratsam, die try/catch-Block in meinem Konstruktor enthalten? Ich weiß, ich könnte den Konstruktor die Ausnahme zurück zum Anrufer werfen lassen. Was bevorzugst du beim Aufruf von Methoden, wie ich es in Constructor gemacht habe? Möchten Sie in der aufrufenden Klasse eine Instanz von FileDataValidator erstellen und die Methoden dort auf dieser Instanz aufrufen? Ich bin nur daran interessiert, Feedback zu hören!

+3

Mehr über was Sie mit 'e' im Falle einer API tun würden,' printStackTrace' riecht lustig. Sicherlich sollten Sie die Benutzer des Codes die Ausnahme auftreten lassen, damit sie etwas dagegen tun können? Dafür gibt es Ausnahmen. –

+0

Warum ändern Sie nicht die 'validateXXX'-Operationen, um boolesche Werte zurückzugeben, und legen Sie dann eine Variable mit dem Namen' valid' fest, wenn alle drei 'validateXXX'-Aufrufe gültig sind. Dann exponieren Sie diese Variable mit einer Methode 'isValid' – cmbaxter

+0

Etwas zu tun mit dem [Befehlsmuster] (http://en.wikipedia.org/wiki/Command_pattern) kann hier helfen; Das bedeutet, dass Sie eine Methode instanziieren, die Sie mehrmals aufrufen, indem Sie die zu überprüfenden Daten übergeben und diese Methode die Ausnahme auslösen lassen. –

Antwort

15

In dem angezeigten Code kommunizieren die Validierungsprobleme nicht mit dem Code, der diese Objektinstanz erstellt. Das ist wahrscheinlich keine gute Sache.

Variante 1:

Wenn Sie die Ausnahme in der Methode/Baumeister fangen, sollten Sie etwas zurück an den Aufrufer übergeben. Sie könnten ein Feld isValid setzen, das auf "True" gesetzt wird, wenn alles funktioniert. Das würde wie folgt aussehen:

private boolean isValid = false; 

public FileDataValidator(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
     isValid = true; 
    } 
    catch(InvalidFormatException e) 
    { 
     isValid = false; 
    } 
} 

public boolean isValid() { 
    return isValid; 
} 

Variante 2:

Oder man könnte die Ausnahme oder eine andere Ausnahme propagiert den Anrufer lassen. Ich habe es als nicht-geprüfte Ausnahme gezeigt, aber tun, was funktioniert nach Ihrer Ausnahme Religion Handhabung:

public FileDataValidator(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
    } 
    catch(InvalidFormatException e) 
    { 
     throw new com.myco.myapp.errors.InvalidDataException(e.getMessage()); 
    } 

} 

Variation 3:

Die dritte Methode, die ich so hat Code erwähnen möchte. Im aufrufenden Code müssen Sie den Konstruktor aufrufen und dann die build() Funktion aufrufen, die entweder funktioniert oder nicht.

String[] lineData = readLineData(); 
FileDataValidator onePerson = new FileDataValidator(); 
try { 
    onePerson.build(lineData); 
} catch (InvalidDataException e) { 
    // What to do it its bad? 
} 

Hier ist der Klassencode:

public FileDataValidator() { 
    // maybe you need some code in here, maybe not 
} 

public void build(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
    } 
    catch(InvalidFormatException e) 
    { 
     throw new com.myco.myapp.errors.InvalidDataException(e.getMessage()); 
    } 

} 

Natürlich ist die build() Funktion eine isValid() Methode, die Sie aufrufen verwenden könnte, um zu sehen, wenn sein Recht, sondern eine Ausnahme von mir den richtigen Weg scheint für die Build-Funktion.

Variation 4:

Die vierte Methode, die ich erwähnen möchte, ist, was ich am besten gefällt. Es hat Code wie diesen. Im aufrufenden Code müssen Sie den Konstruktor aufrufen und dann die build() Funktion aufrufen, die entweder funktioniert oder nicht.

Diese Art von folgt die Art und Weise, wie JaxB und JaxRS arbeiten, die eine ähnliche Situation ist, was Sie haben.

  1. Eine externe Datenquelle - Sie haben eine Datei, sie haben eine eingehende Nachricht im XML- oder JSON-Format.
  2. Code zum Erstellen der Objekte - Sie haben Ihren Code, sie haben ihre Bibliotheken Code entsprechend den Spezifikationen in den verschiedenen JSRs arbeiten.
  3. Die Validierung ist nicht an das Erstellen der Objekte gebunden.

Der Aufrufcode:

String[] lineData = readLineData(); 
Person onePerson = new Person(); 
FileDataUtilities util = new FileDataUtilities(); 
try { 
    util.build(onePerson, lineData); 
    util.validate(onePerson); 
} catch (InvalidDataException e) { 
    // What to do it its bad? 
} 

Hier ist die Klasse Code, wo die Daten leben:

public class Person { 
    private Name name; 
    private Age age; 
    private Town town; 
... lots more stuff here ... 
} 

Und das Dienstprogramm Code zu erstellen und zu validieren:

public FileDataValidator() { 
    // maybe you need some code in here, maybe not 
} 

public void build(Person person, String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 
    setNameFromData(person); 
    setAgeFromData(person); 
    setTownFromData(person); 
} 

public boolean validate(Person person) { 

    try 
    { 
     validateName(person); 
     validateAge(person); 
     validateTown(person); 
     return true; 
    } 
    catch(InvalidFormatException e) 
    { 
     throw new com.myco.myapp.errors.InvalidDataException(e.getMessage()); 
    } 

} 
+0

Ihr erster Typ ist gebrochen (Methoden _within_ im Konstruktor?) Und der zweite ist nur eine Übung in der Redundanz. –

+0

@GrantThomas Ich würde gerne mehr hören. Ich sehe kein Problem beim Aufruf von Methoden im Konstruktor, wenn sie einem nützlichen Zweck dienen. Vielleicht könntest du es erklären. OP müsste entscheiden, was nützlich ist. Zweitens, sagst du, dass das "catch-rethrow" überflüssig ist? –

+1

@LeeMeador Danke, dass du dir so viel Zeit genommen hast, um Ideen zu schreiben! Ich denke, ich werde mit Variation 3 fortfahren. Das Verschieben der Validierungsaufrufe von dem Konstruktor und das Fortsetzen der Ausnahme zu dem Aufrufer ist viel freundlicher in Bezug darauf, ein einzelnes Objekt wiederverwenden zu können, und die aufrufende Klasse ist viel besser dafür geeignet, was zu wissen sollte passieren, wenn ungültige Daten übergeben wurden. – deanmau5

2

Meine Vorliebe ist, dass Ausnahmen mit dem Code behandelt werden, der weiß wie man mit ihnen umgeht. In diesem Fall würde ich annehmen, dass das Bit des Codes, der einen FileDataValidator erzeugt, weiß, was passieren sollte, wenn die Dateidaten nicht gültig sind, und die Exceptions sollten dort behandelt werden (ich befürworte das Weitergeben an den Aufrufer).

Während der Diskussion der besten Praxis - der Klassenname FileDataValidator riecht nach mir. Wenn das Objekt, das Sie erstellen, Dateidaten speichert, würde ich es FileData nennen - vielleicht mit einer Validierungsmethode? Wenn Sie nur Ihre Dateidaten validieren möchten, würde eine statische Methode ausreichen.

+0

+1 für die Kenntnisnahme des Klassennamens muss verbessert werden. –

2

Sie sollten das statische Fabrikmuster berücksichtigen. Machen Sie Ihren all-arguments-Konstruktor privat. Stellen Sie eine statische FileDataValidator (args ...) -Methode bereit. Dies akzeptiert und validiert alle Argumente. Wenn alles in Ordnung ist, kann es den privaten Konstruktor aufrufen und das neu erstellte Objekt zurückgeben. Wenn etwas fehlschlägt, werfen Sie eine Exception, um den Aufrufer darüber zu informieren, dass fehlerhafte Werte angegeben wurden.

Ich muss auch erwähnen, dass dies: catch (Ausnahme e) { printSomeThing (e); }

Ist das tödlichste Antipattern Sie mit Ausnahmen tun könnten. Ja, Sie können einige Fehlerwerte in der Befehlszeile lesen und dann? Der Aufrufer (der die schlechten Werte lieferte) wird nicht über die schlechten Werte informiert, die Programmausführung wird fortgesetzt.

+0

Vielen Dank, dass Sie dieses Muster vorgeschlagen haben. Ich bin sehr für die Implementierung von Mustern mein Code und das ist etwas, mit dem ich sicherlich herumspielen werde. Danke für die Anti-Muster-Beratung auch! Um ehrlich zu sein, ich habe es nur für Dev-Zwecke da, bis ich eine Lösung für die erste Frage gefunden habe! – deanmau5