Codice come:
public Thing[] getThings(){
return things;
}
Non ha molto senso, dal momento che il tuo metodo di accesso non sta facendo altro che restituire direttamente la struttura interna dei dati. Potresti anche dichiarare Thing[] things
di esserlo public
. L'idea alla base di un metodo di accesso è quella di creare un'interfaccia che isola i client dalle modifiche interne e impedisce loro di manipolare la struttura dei dati effettiva, tranne nei modi discreti consentiti dall'interfaccia. Come hai scoperto quando si è rotto tutto il codice client, il tuo metodo di accesso non ha funzionato, è solo un codice sprecato. Penso che molti programmatori tendano a scrivere codice in questo modo perché hanno imparato da qualche parte che tutto deve essere incapsulato con metodi di accesso - ma questo è per i motivi che ho spiegato. Farlo solo per "seguire il modulo" quando il metodo di accesso non serve a nessuno scopo è solo rumore.
Consiglio vivamente la soluzione proposta, che raggiunge alcuni dei più importanti obiettivi dell'incapsulamento: offrire ai clienti un'interfaccia solida e discreta che li isola dai dettagli di implementazione interna della classe e non consente loro di toccare la struttura interna dei dati aspettarti nei modi che ritieni appropriati - "la legge del privilegio meno necessario". Se guardi ai grandi framework OOP popolari, come CLR, STL, VCL, il modello che hai proposto è diffuso, proprio per questo motivo.
Dovresti sempre farlo? Non necessariamente. Ad esempio, se hai classi di aiuto o di amicizia che sono essenzialmente un componente della tua classe lavoratrice principale e non sono "front side", non è necessario - è un eccesso che aggiungerà molto codice non necessario. E in quel caso, non userei affatto un metodo di accesso - è insensato, come spiegato. Dichiara semplicemente la struttura dei dati in un modo che è limitato solo alla classe principale che la utilizza - la maggior parte delle lingue supporta i modi per farlo - friend
o dichiarandola nello stesso file della classe lavoratrice principale, ecc.
L'unico aspetto negativo che posso vedere nella tua proposta è che è più lavoro da codificare (e ora dovrai ricodificare le tue classi di consumatori - ma devi / dovresti farlo comunque.) Ma questo non è davvero un aspetto negativo - devi farlo nel modo giusto, e talvolta ci vuole più lavoro.
Una delle cose che rende buono un buon programmatore è che sanno quando vale il lavoro extra e quando non lo è. A lungo termine, mettere gli extra ora ripagherà con grandi dividendi in futuro - se non su questo progetto, poi su altri. Impara a programmare nel modo giusto e usa la tua testa al riguardo, non solo seguire roboticamente i moduli prescritti.
Si noti che le raccolte più complesse degli array potrebbero richiedere alla classe che lo racchiude di implementare anche più di tre metodi solo per accedere alla struttura interna dei dati.
Se stai esponendo un'intera struttura di dati attraverso una classe contenente, IMO devi pensare al motivo per cui quella classe è incapsulata, se non è semplicemente fornire un'interfaccia più sicura - una "classe wrapper". Stai dicendo che la classe contenente non esiste a tale scopo - quindi forse c'è qualcosa che non va nel tuo design. Valuta di suddividere le tue classi in moduli più discreti e stratificarli.
Una classe dovrebbe avere uno scopo chiaro e discreto e fornire un'interfaccia per supportare tale funzionalità - non di più. Potresti provare a raggruppare cose che non appartengono. Quando lo fai, le cose si rompono ogni volta che devi attuare un cambiamento. Più piccole e discrete sono le tue lezioni, più facile è cambiare le cose: pensa a LEGO.
get(index)
,add()
,size()
,remove(index)
, eremove(Object)
. Utilizzando la tecnica proposta, la classe che contiene questo ArrayList deve avere cinque metodi pubblici solo per delegare alla raccolta interna. E lo scopo di questa classe nel programma è molto probabilmente non incapsulare questa ArrayList, ma piuttosto fare qualcos'altro. L'ArrayList è solo un dettaglio. [...]