Menu
Coddy logo textTech

La convalida nei setter

Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 20 di 61.

Nella lezione precedente, abbiamo creato dei setter di base che si limitano ad assegnare valori. Ma così si perde un vantaggio fondamentale dell'incapsulamento: la possibilità di proteggere i tuoi dati aggiungendo una logica di convalida.

Considera un Counter che non dovrebbe mai diventare negativo. Senza incapsulamento, chiunque potrebbe scrivere c->value = -50 e corrompere lo stato. Con un setter, controlli quali valori sono consentiti:

// counter.c
void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // Rifiuta l'input non valido senza avvisare
    }
    c->value = new_value;
}

Ora i valori negativi vengono semplicemente ignorati.

Potresti anche scegliere di restituire un codice di stato per indicare il successo o il fallimento:

int counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return 0;  // Errore
    }
    c->value = new_value;
    return 1;  // Operazione riuscita
}

Questo schema consente al chiamante di sapere se l'operazione è riuscita. L'intuizione chiave è che i setter non servono solo ad assegnare valori: sono custodi che applicano regole su quali possono essere gli stati del tuo oggetto. Questo è il vero potere dell'incapsulamento: il tuo oggetto mantiene la propria integrità, indipendentemente da ciò che il codice esterno cerca di fare.

challenge icon

Sfida

Facile

Costruiamo un modulo Temperature che protegge i propri dati tramite la convalida nel setter. Creerai un tracker della temperatura che accetta solo valori entro un intervallo valido: vedrai come i setter fungono da guardiani dello stato del tuo oggetto.

Creerai tre file:

  • temperature.h: la tua interfaccia pubblica che usa il pattern del puntatore opaco. Dichiara un tipo Temperature con la sola dichiarazione anticipata. Dichiara queste funzioni:
    • create_temperature: accetta un intero per i gradi iniziali e restituisce un puntatore a Temperature
    • free_temperature: rilascia la memoria allocata
    • temp_get_degrees: getter che restituisce il valore attuale della temperatura
    • temp_set_degrees: setter che restituisce un int (1 in caso di successo, 0 in caso di errore)
    Usa le guardie di inclusione con il simbolo TEMPERATURE_H.
  • temperature.c: definisci la vera struct Temperature con un membro int degrees nascosto. Implementa tutte le funzioni. Il punto fondamentale è il setter. Dovrebbe accettare solo valori compresi tra -50 e 150 (inclusi). Se il valore è fuori da questo intervallo, restituisci 0 e lascia invariata la temperatura. Se è valido, aggiorna il valore e restituisci 1.
  • main.c: mostra la convalida provando a impostare temperature valide e non valide, mostrando che i valori non validi vengono rifiutati, mentre quelli validi vengono accettati.

Riceverai tre input: la temperatura iniziale, una temperatura valida da impostare (entro l'intervallo) e una temperatura non valida da provare (fuori dall'intervallo).

Nel tuo file principale, crea una Temperature con il valore iniziale e stampalo. Poi prova a impostare la temperatura non valida; poiché dovrebbe essere rifiutata, stampa il risultato e mostra che il valore è rimasto invariato. Infine, imposta la temperatura valida, stampa il risultato dell'operazione e mostra il valore aggiornato. Libera la memoria e conferma la pulizia.

Stampa l'output in questo formato:

Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
Freed

Per esempio, con gli input 25, 100 e 200, l'output sarebbe:

Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
Freed

Questo dimostra la vera efficacia dell'incapsulamento. Il tuo setter impone le regole che definiscono una temperatura valida, proteggendo l'integrità dell'oggetto indipendentemente dai valori che il codice esterno cerca di assegnare.

Provalo tu

#include <stdio.h>
#include "temperature.h"

int main() {
    // Leggi gli input
    int initial, valid_temp, invalid_temp;
    scanf("%d", &initial);
    scanf("%d", &valid_temp);
    scanf("%d", &invalid_temp);
    
    // TODO: Crea un oggetto Temperature con il valore iniziale
    
    // TODO: Stampa la temperatura iniziale
    // Formato: "Initial: {degrees}"
    
    // TODO: Prova a impostare la temperatura non valida
    // Stampa il risultato e mostra che il valore rimane invariato
    // Formato: "Set {invalid}: {0 or 1}"
    // Formato: "After invalid: {degrees}"
    
    // TODO: Imposta la temperatura valida
    // Stampa il risultato dell'operazione e mostra il valore aggiornato
    // Formato: "Set {valid}: {0 or 1}"
    // Formato: "After valid: {degrees}"
    
    // TODO: Libera la memoria e stampa "Freed"
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C online