Come affermato da altri, le variabili private sono utili per evitare errori di utilizzo che portano l'oggetto in uno stato incoerente e difficile da rintracciare bug ed eccezioni impreviste.
D'altra parte, ciò che è stato per lo più ignorato dagli altri riguarda i campi protetti.
Una sottoclasse estesa avrà pieno accesso ai campi protetti, rendendo l'oggetto fragile come se tali campi fossero pubblici, ma tale fragilità è limitata alla classe estendibile (a meno che non esponga ulteriormente tali campi).
Quindi, i campi pubblici sono difficili da considerare buoni e fino ad oggi l'unico motivo per usarli è per le classi usate come parametro di configurazione (una classe molto semplice con molti campi e senza logica, quindi quella classe viene passata come parametro da sola a qualche metodo).
D'altra parte, i campi privati riducono la flessibilità del codice ad altri utenti.
Flessibilità vs problemi, pro e contro:
Gli oggetti istanziati dal tuo codice nella classe vanilla con campi protetti sono sicuri e sono di tua esclusiva responsabilità.
D'altra parte, gli oggetti che estendono la tua classe con campi protetti, istanziati dagli utenti del tuo codice, sono la loro responsabilità, non la tua.
Quindi, campi / metodi protetti non ben documentati, o se gli utenti non capiscono davvero come utilizzare tali campi e metodi, hanno buone probabilità di causare problemi inutili a se stessi e a te.
D'altra parte, rendere la maggior parte delle cose private ridurrà la flessibilità degli utenti e potrebbe persino metterli via alla ricerca di alternative mantenute, poiché potrebbero non voler creare e mantenere un fork solo per fare in modo che le cose accadano a modo loro.
Quindi, un buon equilibrio tra privato, protetto e pubblico è ciò che conta davvero.
Ora, decidere tra privato e protetto è il vero problema.
Quando utilizzare protetto?
Ogni volta che capisci che un campo può essere altamente flessibile, dovrebbe essere codificato come protetto. Quella flessibilità è: dal diventare null (dove null è sempre verificato e riconosciuto come uno stato valido senza generare eccezioni), ad avere vincoli prima di essere usato dalla tua classe ex. > = 0, <100 ecc. E riparato automaticamente per i valori di over / under-flow, generando al massimo un messaggio di avviso.
Quindi, per un tale campo protetto potresti creare un getter e usarlo solo (invece di usare direttamente la variabile di campo), mentre altri utenti potrebbero non usarlo, nel caso in cui desiderino una maggiore flessibilità per il loro codice specifico, nel mio esempio potrebbe essere come : se vogliono che i valori negativi funzionino correttamente nella loro classe estesa.