Dovresti mai usare variabili membro protette?

Dovresti mai usare variabili membro protette? Quali sono i vantaggi e quali problemi può causare?

Dovresti mai usare variabili membro protette?

Dipende da quanto sia pignolo riguardo allo stato nascosto.

  • Se non si desidera alcuna perdita di stato interno, dichiarare private tutte le variabili membro è la strada da seguire.
  • Se non ti interessa davvero che le sottoclassi possano accedere allo stato interno, allora protetto è abbastanza buono.

Se uno sviluppatore arriva e sottoclass la tua class, potrebbe rovinarlo perché non lo capisce completamente. Con i membri privati, oltre all’interfaccia pubblica, non possono vedere i dettagli specifici dell’implementazione di come vengono fatte le cose, il che ti dà la flessibilità di cambiarlo in seguito.

Il sentimento generale al giorno d’oggi è che causano un indebito accoppiamento tra le classi derivate e le loro basi.

Non hanno particolari vantaggi rispetto ai metodi / proprietà protetti (una volta potevano avere un leggero vantaggio in termini di prestazioni), e sono stati utilizzati anche in un’epoca in cui l’eredità molto profonda era di moda, cosa che non è al momento.

In generale, se qualcosa non è deliberatamente concepito come pubblico, lo rendo privato.

Se si verifica una situazione in cui ho bisogno di accedere a tale variabile o metodo privato da una class derivata, lo cambio da privato a protetto.

Questo non accade quasi mai – non sono davvero un fan dell’ereditarietà, in quanto non è un modo particolarmente adatto per modellare la maggior parte delle situazioni. In ogni caso, continua, non preoccuparti.

Direi che va bene (e probabilmente il modo migliore per farlo) per la maggior parte degli sviluppatori.

Il semplice fatto è che , se qualche altro sviluppatore arriva un anno dopo e decide di aver bisogno di accedere alla variabile del membro privato, sta semplicemente modificando il codice, cambiandolo in protetto e portando avanti la propria attività.

L’unica vera eccezione a questo è se sei nel business della spedizione di dll binari in forma black-box a terze parti. Questo consiste fondamentalmente in Microsoft, in quelli “Custom DataGrid Control” e forse in altre app di grandi dimensioni fornite con librerie di estensibilità. A meno che tu non sia in quella categoria, non vale la pena spendere tempo / sforzi per preoccuparsi di questo genere di cose.

In generale, manterrei le tue variabili membro protette nel caso raro in cui hai il controllo totale sul codice che le utilizza. Se stai creando un’API pubblica, direi mai. Di seguito, faremo riferimento alla variabile membro come una “proprietà” dell’object.

Ecco ciò che la tua superclass non può fare dopo aver reso protetta una variabile membro piuttosto che privata-con-accessors:

  1. crea pigramente un valore al volo quando la proprietà viene letta. Se si aggiunge un metodo getter protetto, è ansible creare pigramente il valore e restituirlo.

  2. sapere quando la proprietà è stata modificata o cancellata. Questo può introdurre bug quando la superclass fa ipotesi sullo stato di quella variabile. Fare un metodo setter protetto per la variabile mantiene quel controllo.

  3. Imposta un punto di interruzione o aggiungi output di debug quando la variabile viene letta o scritta.

  4. Rinominare quella variabile membro senza cercare attraverso tutto il codice che potrebbe usarlo.

In generale, penso che sarebbe il caso raro che consiglierei di creare una variabile membro protetta. È meglio spendere alcuni minuti esponendo la proprietà attraverso getter / setter che ore dopo rintracciare un bug in qualche altro codice che ha modificato la variabile protetta. Non solo, ma sei assicurato contro l’aggiunta di funzionalità future (come il caricamento lento) senza rompere il codice dipendente. È più difficile farlo più tardi rispetto a farlo ora.

A livello di progettazione potrebbe essere opportuno utilizzare una proprietà protetta, ma per l’implementazione non vedo alcun vantaggio nel mappare questo a una variabile membro protetta piuttosto che a metodi accessor / mutator.

Le variabili membro protette presentano svantaggi significativi perché consentono effettivamente al codice client (la sottoclass) di accedere allo stato interno della class della class base. Questo impedisce alla class base di mantenere efficacemente i suoi invarianti.

Per lo stesso motivo, le variabili membro protette rendono anche la scrittura di codice multi-thread sicuro in modo molto più difficile a meno che non siano garantite come costanti o confinate in un singolo thread.

I metodi di accesso / mutatore offrono molta più stabilità dell’API e flessibilità di implementazione in fase di manutenzione.

Inoltre, se sei un purista OO, gli oggetti collaborano / comunicano inviando messaggi, non leggendo / impostando lo stato.

In cambio offrono pochissimi vantaggi. Non li rimuoverei necessariamente dal codice di qualcun altro, ma non li uso personalmente.

Il problema principale per me è che una volta che si rende protetta una variabile, non è ansible consentire a nessun metodo della class di fare affidamento sul fatto che il suo valore si trovi all’interno di un intervallo, poiché una sottoclass può sempre posizionarlo fuori dall’intervallo.

Ad esempio, se ho una class che definisce la larghezza e l’altezza di un object renderizzabile, e faccio in modo che tali variabili siano protette, non posso quindi fare supposizioni su (per esempio), proporzioni.

Criticamente, non riesco mai a fare quelle ipotesi in qualsiasi momento dal momento in cui il codice viene rilasciato come libreria, poiché anche se aggiorno i miei setter per mantenere le proporzioni, non ho alcuna garanzia che le variabili vengano impostate tramite i setter o accessibili tramite il getter nel codice esistente.

Né nessuna delle sottoclassi della mia class può scegliere di fare quella garanzia, in quanto non possono imporre nemmeno i valori delle variabili, anche se questo è l’intero punto della loro sottoclass .

Come esempio:

  • Ho una class di rettangolo con larghezza e altezza che vengono memorizzate come variabili protette.
  • Una sottoclass ovvia (nel mio contesto) è una class “DisplayedRectangle”, dove l’unica differenza è che limito le larghezze e le altezze a valori validi per una visualizzazione grafica.
  • Ma questo è imansible ora , dal momento che la mia class DisplayedRectangle non può veramente vincolare quei valori, poiché qualsiasi sottoclass di esso potrebbe sovrascrivere direttamente i valori, pur essendo trattata come DisplayedRectangle.

Limitando le variabili a essere private, posso quindi applicare il comportamento che voglio attraverso setter o getter.

La maggior parte delle volte è pericoloso usare protetto perché si interrompe un po ‘l’incapsulamento della class, che potrebbe essere scomposta da una class derivata mal progettata.

Ma ho un buon esempio: diciamo che puoi una sorta di contenitore generico. Ha un’implementazione interna e accessorie interne. Ma devi offrire almeno 3 accessi pubblici ai suoi dati: mappa, hash_map, vettoriale. Allora hai qualcosa come:

 template  class Base { // etc. protected TContainer container ; } template  class DerivedMap : public Base > { /* etc. */ } template  class DerivedHashMap : public Base > { /* etc. */ } template  class DerivedVector : public Base > { /* etc. */ } 

Ho usato questo tipo di codice meno di un mese fa (quindi il codice proviene dalla memoria). Dopo aver riflettuto, credo che mentre il contenitore Base generico dovrebbe essere una class astratta, anche se può vivere abbastanza bene, perché usare direttamente Base sarebbe un tale dolore che dovrebbe essere proibito.

Riepilogo Quindi, hai protetto i dati usati dalla class derivata. Tuttavia, dobbiamo prendere in considerazione il fatto che la class Base dovrebbe essere astratta.

In breve, sì.

Le variabili membro protette consentono l’accesso alla variabile da qualsiasi sottoclass e da qualsiasi class nello stesso pacchetto. Questo può essere molto utile, specialmente per i dati di sola lettura. Tuttavia, non credo che siano mai necessari, perché qualsiasi utilizzo di una variabile membro protetta può essere replicato utilizzando una variabile membro privata e un paio di getter e setter.

Per informazioni dettagliate sui modificatori di accesso .Net vai qui

Non ci sono vantaggi o svantaggi reali per le variabili membro protette, è una questione di ciò che ti serve nella tua situazione specifica. In generale, è prassi comune dichiarare le variabili membro come private e abilitare l’accesso esterno attraverso le proprietà. Inoltre, alcuni strumenti (ad esempio alcuni mapper O / R) si aspettano che i dati degli oggetti siano rappresentati da proprietà e non riconoscano le variabili membro pubbliche o protette. Ma se sai che vuoi che le tue sottoclassi (e SOLO le tue sottoclassi) accedano a una determinata variabile non c’è ragione per non dichiararla come protetta.

Solo per la cronaca, sotto l’Articolo 24 di “Eccezionale C ++”, in una delle note a piè di pagina, Sutter dice “non scriverei mai una class che ha una variabile membro pubblica o protetta.” (Indipendentemente dal povero esempio impostato da alcune librerie .)”