Menu
CoddyTech

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 segnalarlo
    }
    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;  // Successo
}

Questo schema consente al chiamante di sapere se l’operazione è riuscita. L’intuizione chiave è che i setter non riguardano solo l’assegnazione: sono custodi che fanno rispettare le regole su quali valori può assumere lo stato 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 usando la convalida nel setter. Creerai un tracker della temperatura che accetta solo valori compresi in un intervallo valido, dimostrando come i setter fungano 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 solo con una dichiarazione anticipata. Dichiara queste funzioni:
    • create_temperature: accetta un intero per i gradi iniziali e restituisce un puntatore a Temperature
    • free_temperature: libera la memoria allocata
    • temp_get_degrees: getter che restituisce il valore della temperatura attuale
    • temp_set_degrees: setter che restituisce un int (1 in caso di successo, 0 in caso di errore)
    Usa le protezioni di inclusione con il simbolo TEMPERATURE_H.
  • temperature.c: definisci la struct Temperature effettiva con un membro int degrees nascosto. Implementa tutte le funzioni. L'elemento chiave è il setter. Deve 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: dimostra 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 stampala. 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 positivo 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 potenza dell'incapsulamento. Il tuo setter applica le regole che definiscono una temperatura valida, proteggendo l'integrità dell'oggetto indipendentemente dai valori che il codice esterno prova ad assegnargli.

Provalo tu

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

int main() {
    // Leggi i valori di 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