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.
Sfida
FacileCostruiamo 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 tipoTemperaturesolo con una dichiarazione anticipata. Dichiara queste funzioni:create_temperature: accetta un intero per i gradi iniziali e restituisce un puntatore a Temperaturefree_temperature: libera la memoria allocatatemp_get_degrees: getter che restituisce il valore della temperatura attualetemp_set_degrees: setter che restituisce unint(1 in caso di successo, 0 in caso di errore)
TEMPERATURE_H.temperature.c: definisci lastruct Temperatureeffettiva con un membroint degreesnascosto. 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}
FreedPer 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
FreedQuesto 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;
}
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
1Basi di programmazione modulare
File di intestazioneGuardie di inclusioneFile sorgenteFunzioni staticheRipasso: calcolatrice modulare4Incapsulamento
Il concetto di puntatori opachiDefinire struct opacheGetter e setterLa convalida nei setterRiepilogo: scatola segreta2Oggetti e metodi
Le struct come oggettiIl puntatore 'Self'Correttezza constPuntatore o valoreMetodi di supportoRiepilogo: gestore di punti5Progetto: Conto bancario semplice
Configurazione del progettoImplementazione del conto8Polimorfismo
Puntatori a funzione nelle structSimulare i metodiIl concetto di interfacciaImplementare le interfacceIterazione polimorficaRiepilogo: Greeter11Pattern di progettazione in C
Pattern SingletonPattern FactoryPattern IteratorRiepilogo: Factory di Logger3Ciclo di vita degli oggetti
Pattern del costruttorePattern del distruttoreInizializzazione sullo stackCopia profondaRiepilogo: wrapper di stringhe6Ereditarietà tramite composizione
Incorporamento delle structLa regola del primo membroAccesso ai membri della classe baseUpcastingRiepilogo: gerarchia di forme9Progetto: Disegnatore di forme
Panoramica del progettoImplementazione del cerchioImplementazione del rettangoloUtilizzo polimorficoContenitore di formeEsercitati da solo: Compilatore C online