Rendi i metodi che non dipendono dai campi di istanza, statici?


19

Di recente ho iniziato a programmare in Groovy per un framework di test di integrazione, per un progetto Java. Uso Intellij IDEA con il plug-in Groovy e sono sorpreso di vedere un avvertimento per tutti i metodi che non sono statici e che non dipendono da nessun campo di istanza. In Java, tuttavia, questo non è un problema (almeno dal punto di vista dell'IDE).

Tutti i metodi che non dipendono da alcun campo di istanza dovrebbero essere trasformati in funzioni statiche? Se vero, è specifico per Groovy o è disponibile per OOP in generale? E perché?


Questi metodi chiamano altri metodi di istanza? O non hanno letteralmente niente a che fare con un oggetto di quella classe? Puoi fare un esempio?
Ray Toal,

Risposte:


26

Nota che IDEA ha questa ispezione anche per Java, si chiama Metodo può essere "statico" ,

Questa ispezione riporta tutti i metodi che possono essere tranquillamente resi statici. Un metodo può essere statico se non fa riferimento a nessuno dei metodi non statici della sua classe e ai campi non statici e non viene sostituito in una sottoclasse ...

Il fatto è che per il codice Java, questa ispezione è disattivata per impostazione predefinita (il programmatore può accenderlo a propria discrezione). La ragione di ciò è molto probabile che la validità / utilità di tale ispezione potrebbe essere messa in discussione, sulla base di un paio di fonti abbastanza autorevoli.

Per cominciare, il tutorial Java ufficiale è piuttosto restrittivo su quando i metodi dovrebbero essere statici:

Un uso comune dei metodi statici è l'accesso ai campi statici.

Dato sopra, si potrebbe sostenere che l'attivazione dell'ispezione menzionata per impostazione predefinita non è conforme all'uso raccomandato del modificatore statico in Java.

Inoltre, ci sono un paio di altre fonti che arrivano fino a suggerire un approccio giudizioso sull'uso di idee alla base di questa ispezione o addirittura a scoraggiarla.

Vedi ad esempio l'articolo di Java World - Mr. Happy Object insegna metodi statici :

Qualsiasi metodo indipendente dallo stato dell'istanza è un candidato per essere dichiarato statico.

Nota che dico "candidato per essere dichiarato statico". Anche nell'esempio precedente nulla ti costringe a dichiarare instances()come statico. Dichiararlo come statico semplifica la chiamata poiché non è necessaria un'istanza per chiamare il metodo. A volte avrai metodi che non sembrano basarsi sullo stato dell'istanza. Potresti non voler rendere statici questi metodi. In effetti, probabilmente vorrai dichiararli statici solo se devi accedervi senza un'istanza.

Inoltre, anche se puoi dichiarare un metodo come statico, potresti non volerlo a causa dei problemi di eredità che interferisce nella tua progettazione. Dai un'occhiata a "Design orientato agli oggetti efficace" per vedere alcuni dei problemi che dovrai affrontare ...

Un articolo sul blog di test di Google arriva persino a sostenere che i metodi statici sono Death to Testability :

Facciamo un esercizio mentale. Supponiamo che la tua applicazione non abbia altro che metodi statici. (Sì, è possibile scrivere un codice del genere, si chiama programmazione procedurale.) Ora immagina il grafico di chiamata di quell'applicazione. Se si tenta di eseguire un metodo leaf, non si avranno problemi a configurarne lo stato e ad affermare tutti i casi angolari. Il motivo è che un metodo foglia non effettua ulteriori chiamate. Man mano che ti allontani dalle foglie e ti avvicini al main()metodo della radice , sarà sempre più difficile impostare lo stato nel test e sarà più difficile affermare le cose. Molte cose diventeranno impossibili da affermare. I tuoi test diventeranno progressivamente più grandi. Una volta raggiunto ilmain()metodo non hai più un test di unità (poiché la tua unità è l'intera applicazione) ora hai un test di scenario. Immagina che l'applicazione che stai cercando di testare sia un elaboratore di testi. Non c'è molto che puoi affermare dal metodo principale ...

A volte un metodo statico è una fabbrica per altri oggetti. Ciò esalta ulteriormente il problema del test. Nei test ci affidiamo al fatto che possiamo collegare oggetti in modo diverso sostituendo importanti dipendenze con beffe. Una volta newchiamato un operatore, non possiamo sovrascrivere il metodo con una sottoclasse. Un chiamante di una tale fabbrica statica è permanentemente legato alle classi concrete prodotte dal metodo della fabbrica statica. In altre parole, il danno del metodo statico è molto al di là del metodo statico stesso. Inserire il cablaggio del grafico a oggetti e il codice di costruzione nel metodo statico è un problema, dal momento che il cablaggio del grafico a oggetti è il modo in cui isoliamo le cose per i test ...


Vedete, dato sopra sembra naturale che l'ispezione menzionata sia disattivata di default per Java.

Gli sviluppatori IDE avrebbero davvero difficoltà a spiegare perché pensano che è così importante come impostarlo per impostazione predefinita, contro le raccomandazioni ampiamente riconosciuti e best practice.

Per Groovy, le cose sono abbastanza diverse. Nessuno degli argomenti sopra elencati si applica, in particolare quello sulla testabilità, come spiegato ad esempio in Mocking Static Methods nell'articolo di Groovy su Javalobby:

Se la classe Groovy che stai testando rende le chiamate un metodo statico su un'altra classe Groovy, allora potresti utilizzare ExpandoMetaClass che ti consente di aggiungere dinamicamente metodi, costruttori, proprietà e metodi statici ...

Questa differenza è probabilmente il motivo per cui l'impostazione predefinita per l'ispezione menzionata è opposta in Groovy. Mentre in Java l'impostazione predefinita "on" sarebbe fonte di confusione per gli utenti, in Groovy, un'impostazione opposta potrebbe confondere gli utenti IDE.

"Ehi, il metodo non usa i campi di istanza, perché non mi hai avvertito?" A questa domanda sarebbe facile rispondere per Java (come spiegato sopra), ma per Groovy non esiste una spiegazione convincente.


A proposito, ReSharper (realizzato da JetBrains per C # / Visual Studio) suggerisce la stessa cosa
Konrad Morawski,

6
Esiste un'importante distinzione tra metodi statici con e senza effetti collaterali. L'estratto di Google si rivolge davvero al primo.
assylias,

@assylias Lo fa, ma discute anche di come i metodi di fabbrica possano rendere più difficili i test (dal momento che accoppia strettamente le dipendenze nell'applicazione). L'uso di un framework di iniezione delle dipendenze è uno dei migliori rimedi per questo, e risolve anche molti altri problemi.
Per Lundberg,

5

È difficile immaginare che ciò avrebbe alcun effetto percepibile sulle prestazioni. L'unico vantaggio che posso vedere per realizzarli staticè che fornisce un'indicazione visiva che lo stato dell'istanza non è interessato. In altre parole, dice alla persona che legge il codice sorgente qualcosa ... "interessante" su quel metodo, solo perché è lì. La vera domanda è: chiarisce o confonde? "Perché questo metodo è statico? È un metodo di fabbrica? È necessaria la possibilità di chiamarlo senza un'istanza di oggetto?"

Inoltre, ad alcune persone non piacciono i metodi statici, perché sostengono che non puoi deriderli, e quindi non sono testabili, o qualcosa del genere. Certamente, se lo stai rendendo statico per uno dei soliti motivi, come ad esempio fornire un metodo di fabbrica, allora sono tutto per quello. Non sono del tutto sicuro che rendere statici i metodi solo perché non toccano lo stato dell'istanza sia un mandato.


5
Considera che (all'interno di Java) un metodo statico non può essere ignorato. Sebbene non sia spesso un problema, significa che alcune sottoclassi in seguito non possono modificare tale implementazione. Questo non vuol dire che un metodo statico non sia la risposta giusta ma piuttosto una parte delle considerazioni di progettazione.

2
@ user40980 vale la pena considerare, vero, ma vale anche la pena considerare che l'ereditarietà può essere uno strumento goffo che viene spesso utilizzato in modo improprio, e diverse figure di spicco sostengono che tutte le classi dovrebbero essere finalprogettate o specificamente progettate tenendo conto dell'ereditarietà.
Sara

3

Penso che sia possibile attivare il refactoring per essere notato .

Una volta che il metodo è stato reso statico, è chiaro che può essere spostato fuori dalla classe, diciamo a una classe di unità.

È anche facile trasformarlo in un metodo di istanza di uno dei suoi parametri, spesso è qui che dovrebbe essere il codice.


-1

Nota che potresti avere classi stateless che implementano alcune interfacce (es java.lang.Runnable. Non puoi rendere statici i loro metodi. Alcuni pattern (es. Strategia) possono anche produrre oggetti stateless che possono anche avere diversi metodi.

La statica è cugina di primo grado dei singoli. Sarà molto difficile passare dalla statica alla non statica in un momento successivo, quindi quando sarà necessario aggiungere uno stato, si sarà tentati di iniziare a introdurre variabili statiche.


come risponde alla domanda posta?
moscerino il

1
perché è difficile passare da uno stato all'altro? Direi che è il contrario. è più facile contaminare qualcosa di puro che purificare qualcosa di contaminato.
Sara
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.