Incapsulamento Java [duplicato]


Questa domanda ha già una risposta qui:

Diciamo sempre che i dati saranno incapsulati se definiamo semplicemente le variabili private e definiamo i setter getter per accedere a tali variabili. La mia domanda è se possiamo accedere alle variabili (dati) tramite getter e setter, come mai i dati sono nascosto o al sicuro?

Ho cercato su Google molte spiegazioni ma non ho trovato nulla. ognuno ha appena detto nei loro blog e post che si tratta di una tecnica di nascondimento dei dati, ma non l'ha spiegata/elaborata.

In attesa di ottenere una spiegazione appropriata e soddisfacente qui al forum di stackoverflow.

Author: Edwin Dalorzo, 2012-08-15

9 answers

Il modo in cui capisco la tua domanda è, anche se dichiariamo variabili come private, poiché è possibile accedere a tali variabili utilizzando getter e setter, non sono privati. Quindi, qual è il significato di farlo?

Bene, quando si utilizzano getter e setter, è possibile limitare l'accesso alle variabili private.

Cioè

private int x;

public int getInt(String password){
 if(password.equals("RealPassword")){
   return x;
  }
}

E lo stesso per i setter. Spero che questo aiuti!

 14
Author: mithilatw, 2018-03-21 02:03:43

L'incapsulamento è molto più della semplice definizione dei metodi di accesso e mutatore per una classe. È un concetto più ampio di programmazione orientata agli oggetti che consiste nel ridurre al minimo l'interdipendenza tra le classi ed è tipicamente implementato attraverso l'occultamento delle informazioni.

La bellezza dell'incapsulamento è il potere di cambiare le cose senza influenzare i suoi utenti.

In un linguaggio di programmazione orientato agli oggetti come Java, si ottiene l'incapsulamento nascondendo i dettagli utilizzando modificatori di accessibilità (pubblico, protetto, privato, più nessun modificatore che implica il pacchetto privato). Con questi livelli di accessibilità si controlla il livello di incapsulamento, meno restrittivo è il livello, più costoso è il cambiamento quando accade e più la classe è accoppiata con altre classi dipendenti (cioè classi utente, sottoclassi).

Pertanto, l'obiettivo non è quello di nascondere i dati in sé , ma i dettagli di implementazione su come questi dati vengono manipolati.

L'idea è quella di fornire un'interfaccia pubblica attraverso la quale si ottiene l'accesso a questi dati. In seguito è possibile modificare la rappresentazione interna dei dati senza compromettere l'interfaccia pubblica della classe. Al contrario, esponendo i dati stessi, si compromette l'incapsulamento e, quindi, la capacità di modificare il modo in cui si manipolano i dati senza influire sugli utenti. Si crea una dipendenza con i dati stessi e non con l'interfaccia pubblica della classe. Lo saresti creare un cocktail perfetto per i guai quando" change " finalmente ti trova.

Ci sono diversi motivi per cui potresti voler incapsulare l'accesso ai tuoi campi. Joshua Bloch nel suo libro Efficace Java, nel punto 14: Ridurre al minimo l'accessibilità delle classi e dei membri, menziona diverse ragioni convincenti, che cito qui:

  • È possibile limitare i valori che possono essere memorizzati in un campo (cioè il genere deve essere F o M).
  • È possibile eseguire azioni quando il campo viene modificato (evento trigger, convalida, ecc.).
  • È possibile fornire la sicurezza del thread sincronizzando il metodo.
  • È possibile passare a una nuova rappresentazione dei dati (ad esempio campi calcolati, diversi tipi di dati)

Tuttavia, l'incapsulamento è più che nascondere i campi. In Java è possibile nascondere intere classi, nascondendo i dettagli di implementazione di un'intera API. Si pensi, ad esempio, nel metodo Arrays.asList(). Restituisce un'implementazione List, ma non ti interessa quale implementazione, purché come soddisfa l'interfaccia List, giusto?. L'implementazione può essere modificata in futuro senza influenzare gli utenti del metodo.

La bellezza dell'incapsulamento

Ora, a mio parere, per capire veramente l'incapsulamento, bisogna prima capire l'astrazione.

Pensa, ad esempio, al livello di astrazione nel concetto di un'auto. Un'auto è complessa nella sua implementazione interna. Hanno diversi sottosistemi, come un sistema di trasmissione, un sistema frenante, un carburante sistema, ecc.

Tuttavia, abbiamo semplificato la sua astrazione e interagiamo con tutte le auto del mondo attraverso l'interfaccia pubblica della loro astrazione. Sappiamo che tutte le auto hanno un volante attraverso il quale controlliamo la direzione, hanno un pedale che quando lo premi accelera la macchina e controlla la velocità, e un altro che quando lo premi lo fai fermare, e hai una leva del cambio che ti permette di controllare se vai avanti o indietro. Queste caratteristiche costituiscono il interfaccia pubblica dell'astrazione dell'auto. Al mattino puoi guidare una berlina e poi uscirne e guidare un SUV nel pomeriggio come se fosse la stessa cosa.

Tuttavia, pochi di noi conoscono i dettagli di come tutte queste funzionalità sono implementate sotto il cofano. Pensa al tempo in cui le auto non avevano un sistema direzionale idraulico. Un giorno, i produttori di auto inventato, e decidono di metterlo in auto da lì in poi. Tuttavia, questo non ha cambiato il modo in cui gli utenti erano interagire con loro. Al massimo, gli utenti hanno sperimentato un miglioramento nell'uso del sistema direzionale. Un cambiamento come questo è stato possibile perché l'implementazione interna di un'auto è incapsulata. Le modifiche possono essere eseguite in modo sicuro senza influire sulla sua interfaccia pubblica.

Ora, pensare che le case automobilistiche hanno deciso di mettere il tappo del carburante sotto la macchina, e non in uno dei suoi lati. Si va a comprare una di queste nuove auto, e quando si esaurisce la benzina si va alla stazione di servizio, e non si trova il tappo carburante. All'improvviso ti rendi conto che è sotto la macchina, ma non puoi raggiungerla con il tubo della pompa del gas. Ora, abbiamo rotto il contratto di interfaccia pubblica, e quindi, il mondo intero si rompe, cade a pezzi perché le cose non funzionano come ci si aspettava. Un cambiamento come questo costerebbe milioni. Avremmo bisogno di cambiare tutte le pompe di benzina del mondo. Quando rompiamo l'incapsulamento dobbiamo pagare un prezzo.

Quindi, come puoi vedere, l'obiettivo dell'incapsulamento è minimizzare l'interdipendenza e facilitare il cambiamento. Massimizza l'incapsulamento riducendo al minimo l'esposizione dei dettagli di implementazione. Lo stato di una classe dovrebbe essere accessibile solo attraverso la sua interfaccia pubblica.

Ti consiglio davvero di leggere un articolo di Alan Snyder chiamato Incapsulamento ed ereditarietà nei linguaggi di programmazione orientati agli oggetti . Questo link punta al documento originale su ACM, ma sono abbastanza sicuro che sarai in grado di trovare una copia PDF tramite Google.

 47
Author: Edwin Dalorzo, 2017-10-06 13:50:22

I dati sono sicuri, perché è possibile eseguire una logica aggiuntiva nel getter / setter e non è possibile modificare i valori della variabile. Immagina che il tuo codice non abbia funzionato con una variabile null, quindi nel tuo setter puoi controllare i valori null e assegnare un valore predefinito che è != null. quindi il tuo codice funziona ancora, indipendentemente dal fatto che qualcuno tenti di impostare la tua variabile null.

 13
Author: markus, 2012-08-15 09:20:16

La mia domanda è se possiamo accedere alle variabili( dati) tramite getter e setter, come mai i dati sono nascosti o sicuri?

È possibile incapsulare la logica sotto getter / setter per esempio

public void setAge(int age){
 if(age < 0){
  this.age = 0;
 }else{
  this.age = age;
 }
}
 5
Author: Jigar Joshi, 2012-08-15 09:17:52

Continuando alla risposta di Jigar. Ci sono un paio di cose sotto incapsulamento.

  1. Gestione del contratto: Se lo fai public, stai letteralmente facendo cambiare a chiunque quello che vogliono. Non è possibile proteggerlo aggiungendo un vincolo. Il setter può assicurarsi che i dati vengano modificati in modo appropriato.

  2. Mutabilità: Non è sempre necessario avere un setter. Se c'è una proprietà che si desidera mantenere immutabile per il durata dell'oggetto. Basta renderlo privato e non hanno setter per esso. Probabilmente verrà impostato tramite il costruttore. Quindi il tuo getter restituirà semplicemente l'attributo (se è immutabile) o una copia dell'attributo (se l'attributo è mutabile).

 4
Author: Nishant, 2012-08-15 09:24:59

In generale l'incapsulamento dei campi da parte di getter e setter lascia maggiore flessibilità per le modifiche.

Se si accede direttamente ai campi, si rimane bloccati con "campi stupidi". I campi possono essere scritti e letti solo. Nient'altro può essere fatto durante l'accesso a un campo.

Quando si utilizzano metodi si può fare quello che si vuole durante l'impostazione / lettura del valore. Come markus e Jigar menzionato la convalida è possibile. Inoltre si potrebbe decidere un giorno, che il valore è derivato da un altro valore o alcune azioni devono essere eseguite se il valore cambia.

Come mai i dati sono nascosti o sicuri

I dati non sono né nascosti né sicuri utilizzando getter e setter. Ti dà solo la possibilità di renderlo sicuro. Ciò che è nascosto è l'implementazione e non i dati.

 4
Author: Markus Kreusch, 2012-08-15 09:47:39

La convalida dei dati è la risposta principale alla tua domanda su come l'incapsulamento fornisce sicurezza se ci sono accessor e/o mutatori in gioco. Altri hanno menzionato questo usando esempi di avere un fail-safe per impostare un valore predefinito nel mutatore. Hai risposto che preferisci invece lanciare eccezioni, il che è fantastico, ma identificare che hai dati errati quando vai ad usarlo non cambia il fatto che hai dati errati. Non sarebbe quindi meglio prendere il eccezione prima che i dati vengano modificati, ad esempio, farlo nel mutatore? In questo modo i dati effettivi non vengono mai modificati a meno che il mutatore non lo abbia verificato come valido, quindi i dati originali vengono conservati in caso di dati errati.

Sono ancora solo uno studente, ma avevo lo stesso identico come te quando ho incontrato l'incapsulamento, quindi ho passato un po ' di tempo a capirlo.

 2
Author: Grim0013, 2013-06-06 06:11:04

Mi piace la spiegazione quando si prendono in considerazione i thread. Se hai reso pubblici i tuoi campi, in che modo la tua istanza saprà quando un determinato thread ha cambiato uno dei suoi campi? L'unico modo per farlo sarebbe con l'incapsulamento, o più semplice mettere getter e setter a quel campo, quindi SEMPRE conosce e può controllare/reagire agli aggiornamenti dei campi, ad esempio.

 1
Author: Eugene, 2012-08-15 09:22:04

L'incapsulamento rende il codice più facile da riutilizzare da altre persone. Un altro motivo chiave per utilizzare l'incapsulamento è che le interfacce non possono dichiarare i campi, ma possono dichiarare i metodi, che possono fare riferimento a un campo!

I metodi

Sono denominati correttamente con un verbo all'inizio. Ad esempio: getName(), setName(),isDying(). Che può aiutare a leggere il codice!

 0
Author: blockay, 2015-07-25 07:05:57