Che cos’è un invariante di classe?

Nella programmazione e progettazione di computer orientati agli oggetti, un invariante di classe è un insieme di regole che possono essere utilizzate per definire se un’istanza di oggetto esiste in uno stato valido. Dal punto di vista del design, è un insieme di confini tra i quali devono rientrare i dati all’interno di un oggetto per essere considerati in uno stato corretto e funzionale. Può essere definito nella documentazione di progettazione o nei commenti del codice sorgente o, in alcuni linguaggi di programmazione, può essere implementato direttamente in codice informatico utilizzabile. Un programma che utilizza invarianti e asserzioni codificati può causare l’interruzione dell’esecuzione del programma o generare vari errori quando le condizioni invarianti non vengono soddisfatte. A differenza del controllo degli errori standard, gli invarianti di classe vengono generalmente utilizzati solo allo scopo di garantire il funzionamento dell’implementazione interna di una classe e di solito non sono elencati nella documentazione pubblica o nelle interfacce di programmazione.

Da un livello molto elementare, un invariante di classe è essenzialmente una raccolta di asserzioni per una classe. Un’asserzione, sempre in termini semplici, è un’istruzione che controlla una parte dello stato della classe e deve restituire true affinché l’esecuzione del programma continui. Un esempio di un’asserzione è un’istruzione che assicura che un dato intero sia sempre compreso tra 1 e 10. Quando viene utilizzato un invariante di classe, le asserzioni vengono valutate per tutte le parti rilevanti dei dati detenuti dall’oggetto, essenzialmente convalidando che tutti i dati nel oggetto sono all’interno degli intervalli definiti.

In molti casi, l’uso di un invariante di classe è molto simile al controllo degli errori standard, in cui le variabili vengono misurate per assicurarsi che rientrino nei limiti utilizzabili o che non siano nulle. La differenza tra l’utilizzo di invarianti di classe e il controllo degli errori standard, tuttavia, è che gli invarianti e le asserzioni vengono utilizzati principalmente per catturare errori che non dovrebbero verificarsi a meno che non vi sia un difetto intrinseco nel codice. Un’altra differenza è che il controllo degli errori standard tende a coinvolgere il ripristino e le modifiche nel flusso di controllo del programma, mentre il risultato di un errore invariante dovrebbe essere la chiusura del programma. Il motivo per cui la maggior parte dei programmi termina quando un controllo invariante di classe fallisce è perché l’oggetto è in uno stato compromesso e non è in grado, da una prospettiva di progettazione, di soddisfare le sue precondizioni e post-condizioni necessarie per aderire al suo contratto di progettazione.

Una delle proprietà di un invariante di classe nei linguaggi di programmazione orientati agli oggetti in cui sono definiti implicitamente è che l’invariante è un meccanismo ereditato da qualsiasi sottoclasse. Ciò impedisce a una sottoclasse di sovrascrivere eventuali controlli invarianti eseguiti nella classe padre. In definitiva, ciò significa che una sottoclasse non è in grado di rompere il contratto di progettazione stabilito dalla superclasse, il che potrebbe causare risultati imprevedibili o errori di programma difficili da trovare.