L'ambito della classe non è puramente per l'organizzazione? [duplicare]

13

L'ambito non è solo un modo per organizzare le classi, impedendo al codice esterno di accedere a determinate cose a cui non vuoi accedere?

Più in particolare, c'è un guadagno funzionale con i metodi public , protected o private -scoped? C'è qualche vantaggio nel classificare l'ambito metodo / proprietà piuttosto che, ad esempio, solo public -ize tutto?

La mia presunzione dice no semplicemente perché, nel codice binario, non vi è alcun senso dell'ambito (diverso da r / w / e, che non è proprio un campo di applicazione, ma piuttosto autorizzazioni globali per un blocco di memoria). È corretto?

Che dire in lingue come Java e C # [. NET]?

    
posta Qix 23.10.2012 - 09:18
fonte

9 risposte

16

Come fai notare, il motivo principale è per l'organizzazione.

Lo vedo come un canale di comunicazione tra programmatori e manutentori, al fine di rendere chiaro l'intento del progetto e di mantenere il codice pulito il più a lungo possibile.

Ovviamente, questo è vero non solo per OOP ma anche per qualsiasi progetto modulare.

    
risposta data 23.10.2012 - 09:23
fonte
18

Sto scrivendo da una prospettiva Java (per salvarmi dovendo mettere 'da una prospettiva Java' ovunque).

La progettazione accurata di un'API non riguarda solo "l'organizzazione". Molte delle classi pubbliche che scrivo sono utilizzate da molti clienti e utilizzando il modificatore di accesso più basso possibile sono libero di cambiare il funzionamento interno delle mie classi senza infrangere il loro codice (e quindi ottenere cattive telefonate ed e-mail!). / p>

tl; dr : incapsulamento / occultamento delle informazioni, puoi cambiare la tua rappresentazione e il tuo funzionamento interno senza infrangere il codice client, i campi mutabili pubblici non sono thread-safe, promuovi l'immutabilità.

Un modulo ben progettato nasconderà i suoi dati interni e i dettagli di implementazione da altri moduli e separa nettamente la sua API dalla sua implementazione. Ciò significa che la comunicazione tra i moduli avviene solo tramite le loro API e non sono consapevoli del funzionamento interno degli altri.

L'importanza di questo è che disaccoppia i moduli gli uni dagli altri permettendo loro di essere sviluppati, testati, usati, ottimizzati e modificati in isolamento e possono essere sviluppati in parallelo. Aumenta anche il riutilizzo perché i moduli che non sono strettamente accoppiati possono potenzialmente essere utilizzati in altri contesti.

Nel libro di Joshua Bloch "Effective Java" afferma che la regola generale è:

make each class or member as inaccessible as possible. In other words, use the lowest possible access level consistent with the proper functioning of the software that you are writing.

Dopo aver progettato la tua API pubblica, il tuo istinto dovrebbe essere quello di rendere tutto il resto privato, e solo se un'altra classe nello stesso pacchetto ha davvero bisogno di accedere a un membro se lo rendi privato di un pacchetto (rimuovi il modificatore). La necessità di membri protetti in una classe pubblica dovrebbe essere relativamente rara in quanto un membro protetto diventa parte dell'API esportata della classe.

Quando hai tutto come pubblico significa che i campi di dati della classe sono accessibili direttamente e non puoi cambiare la loro rappresentazione senza cambiare l'API. Inoltre, generalmente non è possibile modificare il funzionamento interno della classe in quanto è potenzialmente in grado di infrangere il codice di chiunque stia utilizzando la classe. Questo problema / rischio viene moltiplicato per il numero dei tuoi clienti in quanto la tua classe può essere utilizzata in tutto il luogo.

Se un campo non è definitivo o è un riferimento finale a un oggetto mutabile (ad es. Data) ed è public , si rinuncia alla capacità di limitare ciò che è memorizzato nel campo o applicare invarianti sul campo. Pertanto, se si desidera limitare un int a un determinato intervallo di valori, se il campo public significa che non si ha più il controllo su ciò che è memorizzato nel campo. Inoltre, perdi la capacità di intraprendere qualsiasi azione quando un campo viene modificato, il che significa che le classi con campi mutabili pubblici non sono thread-safe .

I campi

Public final con un oggetto mutabile contengono anche tutti gli svantaggi di un campo non finale. Anche se non puoi modificare il riferimento all'oggetto, l'oggetto può comunque essere modificato, il che può rompere i meccanismi interni della tua classe e avere risultati non intenzionali e disastrosi.

Rendendo i campi privati anche minimizzi la mutabilità della tua classe. Le classi immutabili sono generalmente più facili da progettare, implementare e utilizzare rispetto a quelle mutabili. I campi privati impediscono ai client della tua classe di ottenere l'accesso a oggetti mutabili e di modificare direttamente gli oggetti. In genere, non dai mai ai client nemmeno i riferimenti agli oggetti mutabili (dai loro copie).

Mentre la tua classe riduce al minimo la mutabilità o diventa completamente immutabile diventa anche intrinsecamente thread-safe e non richiede sincronizzazione. Non possono essere corrotti da più thread che li accedono contemporaneamente. Un enorme guadagno funzionale di immutabilità è uno dei modi più semplici per ottenere la sicurezza dei thread.

    
risposta data 23.10.2012 - 10:29
fonte
10

Mi chiedo perché nessuno l'abbia menzionato, ma c'è un possibile guadagno. Come qualcuno ha sottolineato, è possibile ragionare sul comportamento di un programma. Che consentono agli strumenti per l'analisi statica di dirti che una funzione o una variabile non è affatto necessaria (quindi puoi scartarla) o non scritta da nessuna parte (quindi probabilmente non ne hai nemmeno bisogno). Tuttavia potresti prendere in considerazione solo questa organizzazione.

Ma permette anche al compilatore di ottimizzare . Lancia le funzioni e le variabili non necessarie (programma più piccolo) o analizza il flusso del programma in modo che un valore conosciuto possa essere memorizzato nella cache.

    
risposta data 23.10.2012 - 14:56
fonte
8

I mean does having a private method as opposed to a public method give you any sort of advantage as far as how the program works or functions?

Bene, no. Se avessi preso un programma funzionante e innalzato tutti i modificatori di accesso a public , avresti comunque un programma di lavoro *. Allo stesso modo, se hai preso un programma funzionante e sostituito tutti i cicli for e while con equivalenti costrutti goto , avresti anche un programma di lavoro . Allo stesso modo, se hai preso un programma funzionante e hai sostituito tutte le operazioni con le stringhe con equivalenti manipolazioni manuali di char manuali, avresti ancora un programma di lavoro .

Ma "Lavorare" non è l'unica misura della bontà del programma. Anche la leggibilità e la manutenibilità sono caratteristiche, e per quelle , i modificatori di accesso sono utili.

* modulo qualsiasi materiale di tipo Reflection che cerca specifici modificatori di accesso, ecc.

    
risposta data 23.10.2012 - 11:35
fonte
5

Rendendo pubblici i metodi, definisci l'interfaccia della tua classe. In questo modo viene definito come l'altro codice può usarlo e come dovrebbe essere testato. Così definisci in questo modo in che modo l'altro codice può comunicare con esso. La cosa bella è che puoi riscrivere i tuoi interni come metodi privati senza cambiare l'interfaccia.

Questo genera codice riutilizzabile e riduce la quantità di coesione. Usando una vera astrazione dell'interfaccia di classe e assicurandoti ancora di più questa interfaccia.

Vedilo magari come API, non dovresti cambiarlo e renderlo molto chiaro da usare. Gestisci internamente i complessi interni senza renderli visibili.

    
risposta data 23.10.2012 - 09:29
fonte
3

Non ci sono benefici funzionali.

Il vantaggio più importante è che rende possibile ragionare sul comportamento di un programma. Se qualsiasi parte di un sistema può chiamare qualsiasi altra parte, diventa troppo difficile per gli umani mortali effettivi capire il programma e dedurre come si comporterà. Comincerà ad annegare negli insetti e diventerà una grande palla di fango. Un importante traguardo nel miglioramento personale è riconoscere che il tuo cervello è finito e devi mantenere le cose il più semplici possibile per ottenere il massimo da esso.

È anche utile per la comunicazione tra gli sviluppatori. Ma questo non è il vantaggio principale - altrimenti gli sviluppatori solitari svilupperebbero grandi programmi senza organizzarli affatto.

    
risposta data 23.10.2012 - 12:47
fonte
3

Prova a scrivere un'API

Diciamo che vuoi scrivere una biblioteca da condividere con il resto del mondo. Ci sono due cose importanti da considerare.

  • La mia libreria entrerà in conflitto con altre librerie?
  • Come posso impedire agli utenti di dipendere dal codice che potrebbe cambiare in seguito?

Per la prima domanda, le classi forniscono l'ambito per evitare conflitti di denominazione. Basta provare a scrivere codice in JavaScript per un po 'di tempo in cui tutto atterra nello spazio dei nomi globale per impostazione predefinita. Senza implementare qualche forma di spazi dei nomi o classi, può diventare brutto molto rapidamente.

La seconda domanda è controversa. Come utente, voglio essere in grado di vedere l'implementazione interna di metodi / parametri di classi. Come sviluppatore, voglio limitare l'accessibilità dell'utente impedendogli di modificare un'implementazione interna di classi. Molte persone vedono le limitazioni come draconiane ma esistono per una buona ragione.

C'è un semplice detto che racchiude il problema, "se esiste, qualcuno dipenderà da esso."

È lo stesso motivo per cui Windows contiene ancora applicazioni che sono state create nei 3,1 giorni. Le librerie, come le applicazioni, sono significate da utilizzare a lungo termine. Il problema è che hanno anche lo scopo di cambiare ed evolvere nel tempo.

La stabilità deriva dalla progettazione di un'API pubblica stabile. Ciò significa che l'organizzazione della struttura di classe non dovrebbe cambiare e, in caso affermativo, vengono prese misure per garantire la compatibilità con le versioni precedenti.

La flessibilità deriva dal limitare la quantità di codice da cui gli utenti possono dipendere. Vuoi dare loro una struttura che sia nominata abbastanza bene da poter capire cosa fa ma non vuoi mostrare loro come lo fai. Perché, perché il metodo per realizzarlo potrebbe cambiare in futuro.

Se il loro uso supera lo sforzo è discutibile. Nel mondo dei linguaggi dinamici che non si preoccupano dei modificatori di accesso, non fa molta differenza. Se le persone vogliono dipendere dal codice che è interno a una libreria, allora impareranno nel modo più duro perché è una cattiva idea. C'è ancora una nozione di privato / pubblico / globale, ma sono usati per classificare l'ambito, non la politica.

    
risposta data 23.10.2012 - 11:40
fonte
1

In Java (e suppongo che anche in .NET) i modificatori di accesso significano quanto dice SecurityManager. Quindi, se si è in controllo di esso, è possibile accedere ai membri privati attraverso la riflessione.

Ma se il tuo codice viene eseguito in un'altra applicazione in cui SM è impostato per non consentire al tuo codice di eseguire magic magic, non puoi accedere ai membri privati.

Non so se qualcosa del genere sia possibile in C ++ (e suppongo che non lo sia).

Quindi sopra i vantaggi organizzativi (che sono enormi), in alcune lingue dove viene applicato fornisce una differenza funzionale.

    
risposta data 23.10.2012 - 11:32
fonte
1

Per quanto ne so, la maggior parte dei compilatori C ++ spoglia i modificatori di accesso durante la compilazione del codice. Anche C ++ e Java ti danno la possibilità di attraversare questi modificatori (con C ++ puoi davvero accedere a qualsiasi parte della memoria che desideri, e il meccanismo di introspezione / riflessione di Java può permetterti di chiamare il codice contrassegnato come privato) anche se questo può diventare rapidamente non intuitivo e un-performant se abusato, per non parlare del fatto che in entrambi i casi si rende praticamente inutile il rendering del tempo di compilazione quando lo si fa.

Quindi sì, si può dire che i modificatori di accesso sono solo un modo attivo di applicare la "sintassi" dell'API codificata, cose come incapsulamento, occultamento dell'implementazione, ecc. Si può ancora dire che hanno un ruolo "funzionale" come beh, come il compilatore ti avviserà quando stai cercando di violare i modificatori di accesso (tramite i canali "ufficiali") e anche di generare un errore. Questo è un vantaggio funzionale, ad esempio, C, in cui non si può veramente dire al compilatore "questa parte del codice qui NON dovrebbe essere accessibile a quella parte laggiù".

    
risposta data 23.10.2012 - 13:18
fonte

Leggi altre domande sui tag