L'accesso predefinito non rende il modificatore di accesso privato ridondante.
La posizione dei designer linguistici si riflette nel tutorial ufficiale - Controllo dell'accesso ai membri di una classe ed è abbastanza chiaro (per tua comodità, la dichiarazione pertinente nella citazione fatta grassetto ):
Tips on Choosing an Access Level:
If other programmers use your class, you want to ensure that errors from misuse cannot happen. Access levels can help you do this.
- Use the most restrictive access level that makes sense for a particular member. Use private unless you have a good reason not to.
- Avoid public fields except for constants. (Many of the examples in the tutorial use public fields. This may help to illustrate some points concisely, but is not recommended for production code.) Public fields tend to link you to a particular implementation and limit your flexibility in changing your code.
Il tuo ricorso alla testabilità come giustificazione per il completamente eliminazione del modificatore privato è errato, come evidenziato ad esempio dalle risposte in Novità di TDD. Dovrei evitare i metodi privati ora?
Of course you can have private methods, and of course you can test them.
Either there is some way to get the private method to run, in which case you can test it that way, or there is no way to get the private to run, in which case: why the heck are you trying to test it, just delete the damn thing...
La posizione dei progettisti linguistici sullo scopo e l'utilizzo dell'accesso a livello di pacchetto è spiegata in un altro tutorial ufficiale, Creazione e utilizzo dei pacchetti e non ha nulla in comune con l'idea di eliminare i modificatori privati (per comodità, la dichiarazione pertinente nella frase fatta grassetto ):
You should bundle these classes and the interface in a package for several reasons, including the following:
- You and other programmers can easily determine that these types are related...
-
You can allow types within the package to have unrestricted access to one another yet still restrict access for types outside the package...
< rant "Penso di aver sentito abbastanza lamentarsi. Indovina che è ora di dire strong e chiaro ..." >
I metodi privati sono utili per il test dell'unità.
La seguente nota presuppone che tu abbia familiarità con la >> copertura del codice . In caso contrario, dedica del tempo all'apprendimento, poiché è abbastanza utile per coloro che sono interessati al test delle unità e ai test.
Bene, quindi ho ottenuto il metodo privato e i test delle unità, e l'analisi della copertura mi dice che c'è un divario, il mio metodo privato non è coperto dai test. Ora ...
Che guadagno dal mantenerlo privato
Poiché il metodo è privato, l'unico modo per procedere è studiare il codice per sapere come viene utilizzato tramite API non privata. In genere, uno studio di questo tipo rivela che la ragione del divario è che nei test non è presente uno scenario di utilizzo particolare.
void nonPrivateMethod(boolean condition) {
if (condition) {
privateMethod();
}
// other code...
}
// unit tests don't invoke nonPrivateMethod(true)
// => privateMethod isn't covered.
Per motivi di completezza, altre (meno frequenti) ragioni per tali lacune nella copertura potrebbero essere bug nella specifica / progettazione. Non mi tufferò in profondità qui, per mantenere le cose semplici; basti dire che se si indebolisce la limitazione di accesso "solo per rendere testabile il metodo", perderai la possibilità di apprendere che questi errori esistono del tutto.
Bene, per aggiustare il divario, aggiungo un test unitario per lo scenario mancante, ripeto l'analisi della copertura e verifica che non ci sia spazio. Che cosa ho ora? Ho un nuovo test unitario per l'utilizzo specifico dell'API non privata.
-
Il nuovo test garantisce che il comportamento previsto per questo utilizzo non cambierà senza un avviso poiché se cambia, il test fallirà.
-
Un lettore esterno può esaminare questo test e impara come dovrebbe essere usato e comportarsi (qui, il lettore esterno include il mio sé futuro, dato che tendo a dimenticare il codice un mese o due dopo che ho finito con esso).
-
Il nuovo test è tollerante al refactoring (faccio a refactoring metodi privati? si scommette!) Qualunque cosa io faccia a privateMethod
, voglio sempre testare nonPrivateMethod(true)
. Non importa cosa faccio a privateMethod
, non sarà necessario modificare il test perché il metodo non viene invocato direttamente.
Non male? Ci puoi scommettere.
Che cosa posso perdere indebolendo la limitazione di accesso
Ora immagina che invece di sopra, semplicemente indebolisco la limitazione di accesso. Salto lo studio del codice che utilizza il metodo e procedo direttamente con il test che richiama il mio exPrivateMethod
. Grande? Non!
-
Ricerco un test per l'utilizzo specifico di API non private sopra menzionate? No: non c'era nessun test per nonPrivateMethod(true)
prima, e non esiste questo test ora.
-
I lettori esterni hanno la possibilità di comprendere meglio l'utilizzo della classe? No. "- Hey qual è lo scopo del metodo testato qui? - Dimenticalo, è strettamente per uso interno. - Oops."
-
È tollerante per il refactoring? In nessun modo: qualunque cosa cambi in exPrivateMethod
, probabilmente interromperà il test. Rinominare, unire in un altro metodo, cambiare argomento e test smetterà di compilare. Mal di testa? Hai scommesso!
Riassumendo , attenersi al metodo privato mi offre un miglioramento utile e affidabile nei test unitari. Al contrario, l'indebolimento dei limiti di accesso "per testabilità" mi fornisce solo un pezzo di codice di prova oscuro, difficile da capire, che è inoltre a rischio permanente di essere interrotto da qualsiasi refactoring minore; sinceramente, quello che ottengo sembra sospetto come >> debito tecnico .
< / rant >