Vorrei iniziare rispondendo alle tue domande:
-
La rappresentazione dei dati è il tipo di archiviazione dei dati e il significato dei possibili valori di tali dati. Ad esempio, un valore booleano può essere memorizzato come un singolo bit, dove il bit essendo 1
significa verità e 0
significa falsità.
-
La rappresentazione dei dati viene esposta creando qualcosa con un tipo (variabile, membro della classe) visibile all'esterno.
-
Nascondere informazioni significa usare costrutti di linguaggio per impedire che il funzionamento interno di un modulo sia visibile ad altro codice. "Funzionamento interno" può significare tutto ciò che fa sì che il modulo torni, come il fatto che esista un dato, la sua rappresentazione e come vengono determinati i valori (memorizzati, calcolati o entrambi).
Ecco un esempio pratico che dovrebbe rispondere alla domanda che penso tu stia davvero chiedendo in base ad alcuni dei tuoi commenti:
Supponiamo che tu stia sviluppando un'applicazione che ha bisogno di una classe per rappresentare una data. Ti viene in mente qualcosa che non fa nessuno sforzo per nascondere le informazioni, dove tutti i membri sono pubblici e non ci sono metodi per manipolarli:
class Date { // Irrelevant parts left out for brevity
...
public int month; // Month of year, 1 = January
...
}
Il tuo team continua a scrivere molte migliaia di righe di codice che utilizzano Date
, che presuppongono che il primo mese dell'anno, gennaio, sia rappresentato dal valore 1
e raggiunga direttamente la struttura per accedervi:
Date foo;
...
foo.month = 1; // January
...
Un giorno, qualcuno scopre che una funzione critica sarebbe molto più efficiente se ha dato mesi a base zero ( 0
per gennaio, 1
per febbraio, ecc.) invece di dover fare l'aritmetica per produrne una ogni volta che legge o scrive il month
membro di Date
. La direzione decide il business case per fare il cambiamento è buono e dice di farlo accadere.
La funzione critica viene riscritta per utilizzare mesi a base zero, il che significa che ogni altra riga di codice nell'applicazione che si occupa di mesi è ora interrotta perché non utilizza i valori corretti. Può essere compilato perché il valore è ancora un numero intero, ma non utilizza più i valori corretti. Quello che era gennaio ( 1
) ora è febbraio e quello che era dicembre ( 12
) non è più un valore valido perché i mesi a base zero terminano a 11
.
(Questo esempio è un po 'forzato, perché le buone pratiche imporranno che la classe definisca le costanti per valori ben noti come Date.MONTH_JANUARY
, ma abbiate con me. Il principio si applica ancora.)
Correggere il codice danneggiato ti dà molto da fare:
- Identifica ogni uso di
Date
nell'applicazione intera
- Verifica ciascuno di questi usi per determinare se fa o meno supposizioni sul valore del membro
month
- Cambia quelli che fanno per usare le nuove regole
- Ricontrolla tutto
- Mettiti in ginocchio e prega che non ti sia mancato nulla
I costi di questo sforzo possono essere enormi in termini di manodopera per effettuare e testare le modifiche e i rischi per l'azienda se un errore (o la correzione di uno) si tradurrebbe in mancati guadagni.
Se il Date
era stato sviluppato utilizzando l'occultamento delle informazioni in primo luogo, ci sarebbero modi per manipolare il mese che sono indipendenti dal modo in cui sono memorizzati:
class Date {
...
private int month; // Month of year, 1 = January
...
// These methods operate on the month as a 1-based value and
// are the ones all of the existing code uses.
void set_month(int new_month) { month = new_month; }
int get_month() { return month; }
}
Apportare la modifica all'archiviazione basata su zero rende la tua lista di cose da fare molto più piacevole e molto meno rischiosa:
- Riscrivi il membro
month
per indicare che ora è a base zero
- Modifica
set_month()
e get_month()
per eseguire l'aritmetica da convertire in / da uno a zero in base a come in / out
- Verifica i metodi modificati per la correttezza
- Aggiungi e verifica i metodi per eseguire operazioni basate su zero su
month
in modo che la nuova versione della funzione critica possa utilizzarli
La classe ora appare così:
class Date {
...
private int month; // Month of year, 0 = January
...
// These methods operate on the month as a 1-based value and
// are the ones all of the existing code uses.
void set_month(int new_month) { month = new_month - 1; }
int get_month() { return month + 1; }
// New methods that operate on the month as a 0-based value
void set_month_zero(int new_month) { month = new_month; }
int get_month_zero() { return month; }
}
La chiave qui è, ancora una volta, che nulla al di fuori della classe sa nulla su come il mese è memorizzato o anche se è memorizzato del tutto. Tutto ciò che vedono sono due metodi chiamati set_month()
e get_month()
che devono essere utilizzati per memorizzare o recuperare il valore basato su uno. Finché le nuove implementazioni di questi metodi possono essere dimostrate come si comportano come sempre, non è necessario toccare le migliaia di righe di codice che le utilizzano. La funzione critica può utilizzare i nuovi metodi set_month_zero()
e get_month_zero()
per eseguire una manipolazione a base zero del mese.