Clausole di protezione dei nomi che generano eccezioni

6

Ho una funzione evaluate() che analizza un String per alcune variabili e le sostituisce con il valore corrispondente:

public String evaluate() {
    String result = templateText;
    for (Entry<String, String> entry : variables.entrySet()) {
        String regex = "\$\{" + entry.getKey() + "\}";
        result = result.replaceAll(regex, entry.getValue());
    }
    if (result.matches(".*\$\{.+\}.*")) {    //<--check if a variable wasn't replaced
        throw new MissingValueException();
    }
    return result;
}

Poiché la funzione evaluate() ora fa 2 cose, prima sostituisce le variabili con i valori AND controlla eventuali variabili che non sono state sostituite, ho pensato di rifarlo a:

public String evaluate() {
    String result = templateText;
    for (Entry<String, String> entry : variables.entrySet()) {
        String regex = "\$\{" + entry.getKey() + "\}";
        result = result.replaceAll(regex, entry.getValue());
    }
    checkForMissingValues(result);
}

private void checkForMissingValues(String result) {
    if (result.matches(".*\$\{.+\}.*")) {
        throw new MissingValueException();
    }
}

Questo è un buon nome per la funzione checkForMissingValues ? Voglio dire controlla i valori mancanti, ma genera anche un'eccezione.

Ho pensato di rinominarlo in throwExceptionIfMissingValueWasFound() , ma questo nome dice a COME la funzione lo fa più di CHE COSA sta facendo la funzione.

Esiste uno standard per denominare tali funzioni che verificano una condizione quindi genera un'eccezione?

    
posta Songo 25.02.2013 - 13:13
fonte

7 risposte

2

Perché non lo chiami guardAgainstMissingValues() è semplice e trasmette il messaggio direttamente.

Basta chiedersi cosa fa questa funzione? guards contro i valori mancanti. Hai detto tu stesso che si tratta di una clausola di salvaguardia, quindi perché non lo chiami di conseguenza.

Inoltre, ritengo che il termine clausola di salvaguardia implichi un controllo nella sua implementazione, quindi non dovrai menzionare esplicitamente il controllo nel nome della funzione.

    
risposta data 26.02.2013 - 20:33
fonte
2

Di solito uso ensureThisOrThatAttribute , che, in combinazione con una dichiarazione di throws CustomMadeException esplicita, rende le cose abbastanza chiare.

Tuttavia, più importante del conformarsi ad alcuni presunti standard generali è che ti conformi allo standard tuo proprio codice di base. Se non ne hai ancora uno, beh, scegli un formato ora e prosegui con esso.

    
risposta data 25.02.2013 - 13:33
fonte
2

Di solito preferisco una convenzione come questa:

static class Guard {
  public static void IsNotNull(value) {
    if(value == null) {
      throw new MyCustomGuardException();
    }
  }
}

Più tardi quando lo usi:

public function DoSomething(DateTime startedAt) {
  Guard.IsNotNull(startedAt);
}

Un esempio più completo di una classe di guardia fluente può essere trovato nel pacchetto NetFX qui:

link

    
risposta data 25.02.2013 - 14:08
fonte
2

Il tuo nome di routine mi sembra perfetto. Cosa c'è di male in "controllo"?

Tendo a romperlo, però. Quindi ho una routine che fa il check / throw, oltre alle funzioni che fanno i test effettivi. Avresti finito con qualcosa del tipo:

check(!hasMissingValues(result));

Questo rende più di una semplice convenzione di denominazione. Puoi chiamarlo "validate" o "enforce" o qualsiasi altra cosa, ma la chiave che check ha un comportamento definito.

(Questo ovviamente presuppone che il tipo di condizioni che stai check ing non ha bisogno di un sacco di informazioni sulle eccezioni personalizzate, ma spesso è così.)

    
risposta data 26.02.2013 - 03:31
fonte
0

Non penso che questo garantisca un metodo separato. Ho notato anche diverse cose:

Crei un oggetto Pattern per ogni variabile in Map . La creazione di oggetti modello è costosa (richiede l'analisi). Quindi valuti la regex sulla stringa con replaceAll . Quindi se si hanno 100 variabili che diventano 100 regex analizzate e create, la stringa viene scansionata 100 volte. Questo è inefficiente.

La tua espressione regolare per cercare le variabili mancanti è estremamente costosa. Analizzerà ogni carattere nella stringa molte molte volte, specialmente se contiene ${ .

Quello che devi fare è capovolgere la logica. Trova le stringhe ${x} nel testo e recupera le variabili dalla tua mappa per riempirla, generando un'eccezione la prima volta che incontri una variabile mancante.

public String evaluate() {
    Matcher matcher = Pattern.compile("\$\{(\.+?\)}").matcher(templateText);
    StringBuilder result = new StringBuilder(templateText.length());
    while(matcher.find()) {
        String val = variables.get(matcher.group(1));
        if (val == null) throw new MissingValueException();
        matcher.appendReplacement(result, val);
    }
    matcher.appendTail(result);
    return result.toString();
}

Questo cercherà la stringa solo una volta con una sola regex. Fallirà sulla prima variabile mancante. Se hai definito 100 variabili ma solo 1 appare nel modello, viene eseguita solo una sostituzione.

    
risposta data 26.02.2013 - 16:38
fonte
0

Prima di tutto, i metodi in C # seguono la convenzione Pascal, quindi dovrebbe essere valutato e non valutato.

Secondo: è naturale che i metodi generino eccezioni in scenari eccezionali, così NON DEVI nominare il tuo metodo per significare questo.

Terzo: non è normale lanciare un'eccezione a causa di un controllo interno (a meno che non si abbia una necessità specifica). Idealmente, il metodo dovrebbe restituire un valore booleano che indica se il controllo è riuscito o meno. Quindi la firma del metodo dovrebbe idealmente essere:

private bool IsMissingValues(String result) 

Successivamente, il nome di un metodo non deve sempre spiegare ogni singolo dettaglio di ciò che fa, lo legge sempre insieme alla classe in cui è definito.

Quindi, String.Replace è sufficiente; String.ReplaceThisStringWithAnother è overkill.

A proposito, il metodo di valutazione dovrebbe essere idealmente chiamato Sostituisci o qualcosa come quello che essenzialmente fa.

Anche i metodi privati possono essere relativamente meno "prolissi" di quelli pubblici poiché nessun altro, tranne te, lo vedrà (ok bene, è discutibile).

    
risposta data 26.02.2013 - 17:12
fonte
0
public String evaluate() {
    String result = replaceVariablesWithValues();
       // Extract the for loop code to the new method listed above

    if (resultContainsVariables(result)) {    
         // All variables should have been replaced
        throw new MissingValueException();
    }
    return result;
}

In alto è la mia proposta su come refactoring.

  1. La funzione di valutazione proposta descrive sinteticamente sia la funzionalità generale (sostituire le variabili con i valori) sia il caso di eccezione (se il risultato contiene variabili, genera un'eccezione).
  2. I dettagli delle valutazioni regex devono essere estratti nelle funzioni di supporto perché non è necessario analizzare mentalmente la regex per comprendere il contratto e controllare il flusso di valutazione. Inoltre, suggerisco di fare il prefisso regex e le costanti del suffisso.
  3. Suggerisco di mantenere l'affermazione di tiro in valutazione. Non è ovvio ciò che fa una funzione di "controllo" o di guardia, ma sapere cosa serve a tale funzione è necessario per capire il contratto di valutazione.
risposta data 26.02.2013 - 17:20
fonte

Leggi altre domande sui tag