2013-06-30 13 views
5

La mia domanda riguarda Java, ma può anche essere applicata a C#. Mi chiedevo perché tutti consigliano di rendere le variabili di istanza private invece di renderle protette da .Perché si consiglia di dichiarare variabili di istanza come private?

Pensaci. Le variabili private non sono viste dalla sottoclasse, quindi se ho bisogno di accedere o modificare le variabili della superclasse nella mia sottoclasse sono costretto a usare un metodo di accesso e mutatore come getMyPrivateVariable o setMyPrivateVariable. Ma quando estendi qualche classe ed erediti i suoi membri, questo funziona come se li avessi dichiarati direttamente nella sottoclasse. Quindi logicamente ciò significa che la sottoclasse dovrebbe anche avere accesso diretto alle variabili di istanza e fare un caso per progettare la classe con variabili protette. Capisco che una simile pratica romperebbe l'incapsulamento, ma ciò sembra irrilevante nel caso dell'ereditarietà, perché, ancora una volta, in questo caso tutto funziona come se i membri della superclasse fossero dichiarati nel sottolocalcio, quindi il sottoprodotto ha un "diritto naturale" per poter accedere direttamente ai suoi membri, indipendentemente dal fatto che siano stati ereditati o meno. L'incapsulamento, a mio parere, è più importante per l'interfacciamento con l'oggetto con altri oggetti che si trovano all'esterno dell'albero di ereditarietà dell'oggetto.

Quindi, la mia domanda è perché tutti consigliano di dichiarare le variabili di istanza della classe come private piuttosto che protette?

+0

Questa è una domanda adatta per programmers.stackexchange.com piuttosto che StackOverflow. – m3th0dman

+0

Non _everyone_ fa. Ma dal tuo testo sembra che tu abbia il punto di "protetto"; in ogni caso, fai ciò che ritieni giusto. – fge

+5

Solo perché una classe consente l'ereditarietà non significa che voglia consentire la corruzione arbitraria dei suoi invarianti interni da classi figlio. Rendere i campi (e alcuni metodi) 'private' lo consente. – dlev

risposta

1

Rispondete voi stessi - incapsulamento.

Ad esempio, si dispone di una classe Cat astratta. Questo definisce la velocità della variabile membro - cioè quanto velocemente funziona.

La classe astratta definisce anche un metodo finale di esecuzione che ovviamente aggiorna la velocità.

Ora - se sottoclassi di Cat - ad es. Moggy o Tabby potevano accedere e modificare la "velocità" direttamente, in modo da interrompere il metodo di esecuzione.

Quindi meglio tenerlo legato dove inizia. Puoi anche dichiararlo localmente se necessario.

0

se ho bisogno di accedere o modificare le variabili ereditarie nel mio sottoclasse sono costretto a usare un po 'di accesso [...]

Là lo avete sbagliato: private membri non sono ereditato . Potresti confondere il significato di "ereditare" con il fatto che l'istanza della sottoclasse possiede tutti i membri delle sue superclassi.

Il modo migliore per vedere cosa significa che i membri privati ​​non sono ereditati sta osservando che la sottoclasse può dichiarare il proprio membro privato e questo non può mai causare uno scontro con il membro privato di una superclasse con lo stesso nome. I due coesistono pacificamente.

I membri sono dichiarati protected solo quando progettazione di una classe specfically da utilizzare per la creazione di sottoclassi: in questo caso le protected membri sono infatti una parte della sua API pubblica. La maggior parte delle classi sono non progettate per l'estensione pubblica, ma dichiararle final spesso non è un'opzione. Se tali classi avessero tutti i loro membri protected, equivarrebbe a renderli public poiché qualsiasi codice client potrebbe banalmente rendere la sua sottoclasse fittizia, non aggiungendo nulla al genitore, ma esponendo i suoi interni.

+0

Marko, mi sono sbagliato. So che le variabili private non sono accessibili da una sottoclasse, ma sono protette. Questo è il punto centrale della mia domanda: perché nascondere la struttura dati della superclasse dalla sottoclasse. – akhilless

+0

Hai detto che vuoi accedere alle variabili ereditate, che non sono accessibili; a cui rispondo, "non sono ereditati". –

+0

Mi chiedevo sulla validità di dichiarare le variabili di istanza private anziché protette. La parte che stai citando dice che "Le variabili private non sono viste dalla sottoclasse", quindi so che non sono ereditate. Ho corretto l'errore di battitura e ho rimosso questa parola "ereditata" da quel luogo per rendere più chiara la mia linea di pensiero. Sulla mano, non pensi che creare una sottoclasse fittizia che espone l'accesso alle variabili ereditate (protette) della superclasse esponga effettivamente gli interni del sublcass, dal momento che non puoi chiamare questi metodi sull'oggetto della superclasse? – akhilless

0

Considerare la seguente "regola generale": tutto ciò che è visibile dall'esterno della classe diventa parte di un contratto con il mondo esterno. Per mantenere la tua libertà di modificare il tuo codice come desideri con un impatto minimo, il tuo obiettivo è limitare la visibilità al minimo possibile - le persone di solito non limitano la loro libertà a meno che non siano obbligati a farlo.

In altre parole, è necessario disporre di un motivo per dichiarare un membro diverso da private. Una volta che si dispone di un motivo valido, aumentare la visibilità al minimo possibile (la prima scelta deve essere pacchetto privato/default visibilità). Questo perché si suppone di avere il pieno controllo (o almeno avere un po 'di controllo) del codice nel pacchetto, quindi le modifiche possono essere eseguite separatamente. Come nota a margine, "pacchetto privato" è l'unico livello di visibilità (diverso da public) che può essere applicato alle classi di livello superiore. Pertanto, dovresti considerare di rimuovere il modificatore public da classi che non sono utilizzate al di fuori del loro pacchetto.

La visibilità di protected "sfugge" al proprio raggio di controllo, poiché qualsiasi client può fare affidamento su quella particolare variabile o metodo.

Per quanto riguarda public, è consigliabile utilizzarlo solo per i metodi dichiarati nelle interfacce implementate.

0

Se si rendono le variabili di istanza protette ed è possibile eseguire la sottoclasse della classe (poiché non è final), tutti possono eseguire la sottoclasse della classe e modificare le variabili di istanza quando non se ne prevedono. Ciò aumenta enormemente la possibilità che la tua funzionalità non si comporti nel modo desiderato. Devi affrontare una grande varietà di come la tua classe può essere utilizzata, il che rende molto difficile per te assicurarti che ogni possibile modifica delle tue variabili di istanza produca il risultato atteso in qualsiasi momento possibile in cui viene modificato.

0

IMHO è una domanda filosofica. Ma immagino che si tratti di aggiungere un livello di sicurezza per accedere alle variabili di istanza.

Esponendoli tramite getter e setter, si garantisce che verranno acceduti correttamente (ad esempio, per valori non compresi nell'intervallo) relativi al ruolo della classe. Ti stai anche preparando per gli interventi futuri, isolando le responsabilità (ad esempio se ad un certo punto ti rendi conto che l'elaborazione dovrebbe essere eseguita sistematicamente su una particolare variabile, allora hai solo un metodo per perfezionare, in teoria non toccare nient'altro e, soprattutto, non rompere la funzionalità dell'intero programma). Hai anche la libertà di definire alcuni di loro in sola lettura, fornendo solo un metodo getter.

Quindi in sostanza aggiunge un livello di sicurezza e offre un maggiore controllo sulle variabili.

Inoltre, poiché sono chiamate variabili di istanza, per me è logico che solo l'istanza effettiva possa accedervi direttamente.

0

essenza della programmazione orientata agli oggetti è l'invio del messaggio, che significa favorising comportamento oltre dati.

Il motivo per evitare di esporre le variabili è rendere il software il più possibile flessibile.

I client non devono prendere alcuni dati da qualsiasi luogo e implementare la logica da soli (logica che non fa parte della loro responsabilità), dovrebbero Tell! Don't Ask!. Non dovrebbero padroneggiare l'algoritmo necessario, che dovrebbe essere il ruolo della classe di destinazione.

Lasciando la variabile protected in una classe base (o classe finale ..), si consente alle sottoclassi di modificarle, e molto spesso molto spesso le sottoclassi potrebbero non avere la conoscenza né la responsabilità di farlo. Spesso porta a qualche bug misterioso, come l'assegnazione di un valore inaspettato alla classe base di un campo da sottoclassi. Ovviamente, per alcuni casi è necessario protected, ma solo quando la sottoclasse è interessata dalla stessa responsabilità.

Pertanto, rendere sempre il campo variabile/metodo più restrittivo possibile. Il tuo codice sarà così, protetto, flessibile, facilmente unit-testabile (poiché concentrato su un singolo posto) ed esente da molti bug abituali quando esponi le variabili di istanza al client. E soprattutto, la tua classe potrebbe cambiare i loro interni senza infrangere il codice cliente.

Inoltre, evitare getter/setter quando non si ha a che fare con la struttura dei dati. In effetti, questo promuoverà metodi comportamentali.

Infatti, nel 95% dei casi, getter/setter sono molto poveri (non implementano una logica valida), e sono solo una fine corsa per rendere la variabile public/protected.

Problemi correlati