- Objects are responsible for preserving the integrity (e.g.,some invariant) of the data representation.
Un invariante è solo qualcosa che deve rimanere vero in ogni momento. Ad esempio, se hai un oggetto che rappresenta un intervallo di qualche tipo e memorizza un limite inferiore (chiamiamolo a
) e un limite superiore ( b
), un invariante sarebbe il requisito che a <= b
.
L'oggetto manterrebbe questa invariante impedendo al codice client (il codice che lo utilizza) di cambiarlo in un modo che si traduca in a > b
. Ad esempio, supponiamo che l'utente possa impostare questi due valori; nel metodo / proprietà setter, prima di accettare il valore fornito dall'utente, verificherebbe se a > b
, e genererà un'eccezione se lo è, o userà qualche altro meccanismo per mantenere l'invariante.
- The data representation is hidden from other objects
Questo è noto come incapsulamento ; in pratica, si fornisce un insieme limitato di metodi pubblici (l'interfaccia pubblica) che altri oggetti possono utilizzare per interagire con questo oggetto. Questo è come un "contratto" pubblico: il tuo oggetto dichiara fondamentalmente "Fornisco questi servizi, in questo modo e in questo formato". Tuttavia, lo stato interno può essere rappresentato e manipolato in vari modi (è possibile avere varie implementazioni ) purché l'oggetto confermi all'interfaccia definita. Questo stato interno è "invisibile" agli altri oggetti, il che è una buona cosa: ciò ti consente teoricamente di modificare i dettagli di implementazione dell'oggetto senza influenzare (e quindi dover modificare) il codice in qualsiasi altra parte del sistema.
Ad esempio, considera un semplice gioco in cui hai un livello che è una griglia NxN con alcuni elementi su di esso.
// (pseudocode)
class Grid
{
// represent items locations as an NxN 2D array of Booleans
// (omitted)
bool IsItemOn(x, y)
{
// check the 2D Boolean array
}
}
Tuttavia, per una ragione o per l'altra, decidi di cambiare la rappresentazione interna dall'array booleano 2D a una matrice booleana 1D:
class Grid
{
// represented as 1D array of NxN Booleans
// (omitted)
bool IsItemOn(x, y)
{
// calculate the index into the 1D array from x and y
// check the value at the calculated index
}
}
Tuttavia, a causa di alcune altre considerazioni, in seguito si decide di modificare lo schema e di memorizzare solo l'elenco delle posizioni degli articoli. Forse ci sono solo 3 elementi nel livello e sembrava inutile usare una serie di elementi NxN. In questo modo, memorizzerai solo 3 punti bidimensionali.
class Grid
{
// just store item locations as (x, y)
// (omitted)
bool IsItemOn(x, y)
{
// check if this location matches any of the ones stored
}
}
In tutti i casi, solo la rappresentazione interna cambia e qualsiasi codice esterno rimane inconsapevole di quello, poiché è solo il metodo IsItemOn che è visibile dall'esterno. Nessun altro codice deve essere modificato, tutto funziona così com'è.