I metodi di una classe dovrebbero chiamare i propri getter e setter?

51

Dove lavoro vedo molte classi che fanno cose del genere:

public class ClassThatCallsItsOwnGettersAndSetters {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        setField("value");
        //do stuff
        String localField = getField();
        //do stuff with "localField"
    }
}

Se avessi scritto questo da zero, avrei scritto invece methodWithLogic() in questo modo:

public class ClassThatUsesItsOwnFields {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        field = "value";
        //do stuff            
        //do stuff with "field"
    }
}

Sento che quando la classe chiama i propri getter e setter, rende il codice più difficile da leggere. Per me quasi implica che la logica complessa stia accadendo in quel metodo, anche se nel nostro caso non lo è quasi mai. Quando eseguo il debug di un codice non familiare, chi può dire che l'errore non è un qualche effetto collaterale in quel metodo? In altre parole, mi fa fare molti viaggi secondari nel viaggio di comprensione del codice.

Ci sono benefici per il primo metodo? Il primo metodo è effettivamente migliore?

    
posta Daniel Kaplan 04.01.2013 - 21:20
fonte

9 risposte

46

Non dirò che è meglio o peggio, perché ciò dipende in parte dalla tua situazione (secondo me). Ma considera che i tuoi getter e setter potrebbero cambiare implementazione in un secondo momento, e scavalcarli significherebbe saltare quella logica.

Ad esempio, cosa succede se aggiungi un flag "sporco" ad alcuni campi setter in seguito? Chiamando i tuoi setter nel tuo codice interno imposterai la bandiera dirty senza cambiare nessun altro codice. In molte situazioni questa sarebbe una buona cosa.

    
risposta data 04.01.2013 - 21:34
fonte
31

Chiamare direttamente il setter non è, di per sé, un problema. La domanda dovrebbe essere davvero: perché il nostro codice ha setter ovunque?

Le classi mutevoli sono un gioco pericoloso, in particolare quando la classe stessa gestisce il proprio stato. Considera quanti di questi setter hanno veramente bisogno di esistere. Quanti potrebbero essere impostati nel costruttore e quindi incapsulati interamente dalla classe stessa?

Se il campo deve essere impostabile esternamente, chiediti se il metodo con la logica dovrebbe essere presente. La tua classe è davvero solo una classe data / statale? Questa classe ha più di una responsabilità?

Non fraintendermi, ci saranno casi in cui ciò andrà bene. Non sto dicendo che dovresti eliminare completamente i setter sulle classi con la logica interamente. Ma queste dovrebbero essere l'eccezione, non la regola. E, in quei pochi casi, dovrebbe essere ovvio quale accedere direttamente.

    
risposta data 04.01.2013 - 21:49
fonte
9

Sì, i metodi della tua classe dovrebbero chiamare getter e setter. L'intero punto nello scrivere getter e setter è la prova futura. È possibile rendere ogni proprietà un campo e esporre direttamente i dati agli utenti della classe. Il motivo per cui costruisci getter e setter non è necessariamente perché ora c'è una logica complessa, ma in modo che l'interfaccia non si interrompa in futuro se devi aggiungerla.

    
risposta data 04.01.2013 - 21:33
fonte
6

Per rispondere alle tue domande in una parola, sì.

Avere una classe chiama i propri getter e setter aggiunge estensibilità e fornisce una base migliore per il codice futuro.

Dì che hai qualcosa di simile a questo:

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        this.year = year;
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}

Chiamare i setter per anno e fare al momento non può aggiungere alcuna funzionalità, ma cosa succede se si desidera aggiungere qualcosa come la convalida dell'input ai setter?

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        if(year > 0)
        {
            this.year = year;
        }
        else
        {
            System.out.println(year + " is not a valid year!");
        }
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}
    
risposta data 05.01.2013 - 08:48
fonte
5

Una cosa che non è stata menzionata è che getter e setter (come tutti i metodi) sono virtuali in Java. Questo aggiunge un'altra funzionalità per utilizzarli sempre nel codice. Un altro utente potrebbe estendere la tua classe, sovrascrivendo i tuoi getter e setter. La tua classe base userebbe quindi i dati della sottoclasse invece dei suoi. In una lingua in cui contrassegni in modo esplicito le funzioni virtuali, questo è molto più pratico in quanto puoi prevedere e dichiarare quali funzioni possono essere eseguite. In Java, questo è qualcosa che dovresti sempre essere a conoscenza. Se è il comportamento desiderato, utilizzarli nel tuo codice è una buona cosa, altrimenti non così tanto.

    
risposta data 09.01.2013 - 15:30
fonte
3

Se stai cercando di realizzare qualcosa che è fornito dall'interfaccia pubblica, usa i getter / setter.

Tuttavia, in qualità di proprietario / sviluppatore della classe, sei autorizzato ad accedere alle sezioni private del tuo codice (all'interno della classe ovviamente), ma sei anche responsabile della mitigazione dei pericoli.

Quindi forse hai un getter che itera su qualche lista interna, e vuoi ottenere il valore corrente senza incrementare l'iteratore. In questo caso, utilizza la variabile privata.

public class MyClass
{
    private int i;
    private List<string> list;
    public string getNextString()
    {
        i++;
        return list[i];
    }

    private void getString()
    {
        // Do not increment
        string currentString = list[i];

        // Increment
        string nextString = getNextString();
    }
}
    
risposta data 04.01.2013 - 21:46
fonte
1

Sì. Getter e setter rappresentano lo stato, quindi cambia questa domanda - vuoi tenere traccia di diversi modi di modificare lo stato di un oggetto nello stesso modo, a meno che non sia necessario?

Meno cose devi tenere traccia delle migliori: ecco perché gli oggetti immutabili sono più facili da gestire.

Considera che non c'è nulla che ti impedisca di avere sia un campo pubblico che un getter / setter pubblico - ma cosa guadagneresti?

Potrebbe essere necessario desiderabile o persino necessario per accedere direttamente al campo per uno o più motivi, non dovresti evitare di farlo se ciò accadesse. Ma dovresti farlo solo se c'è un vantaggio definito nel farlo.

    
risposta data 05.01.2013 - 09:58
fonte
1

Entrambi i metodi hanno i loro casi d'uso. Poiché il setter pubblico mantiene coerenti il valore del campo (e / oi valori associati), è necessario utilizzare setter quando la logica del metodo non interferisce con questa logica di coerenza. Se hai appena impostato la tua "proprietà", usa setter. D'altra parte, ci sono situazioni in cui è necessario l'accesso diretto ad alcuni campi, ad esempio operazioni di bulk con setter pesante o operazioni in cui il concetto di setter è troppo semplice.

È tua responsabilità mantenere le cose coerenti. Setter lo fa per definizione, ma non può coprire casi complessi.

    
risposta data 05.01.2013 - 19:18
fonte
1

Direi No ..

Se i tuoi getter / setter si limitano a ottenere e impostare (nessuna inizializzazione pigra, nessun controllo, ecc.), allora usa solo le tue variabili. Se in futuro cambi i tuoi getter / setter, puoi benissimo cambiare il tuo methodWithLogic() (perché la tua classe sta cambiando) e puoi chiamare un getter / setter invece dell'assegnazione diretta. È possibile documentare questa chiamata per il getter / setter (poiché sarà strano chiamare un getter / setter quando il resto del codice classe utilizza direttamente la variabile).

La JVM effettuerà chiamate in linea ai getter / setter. Quindi, non è mai un problema di prestazioni. Il guadagno nell'uso delle variabili è la leggibilità e IMHO, lo farei.

Spero che questo aiuti ..

    
risposta data 09.01.2013 - 15:06
fonte

Leggi altre domande sui tag