Validation dans les setters
Fait partie de la section Object Oriented Programming du Journey C de Coddy — leçon 20 sur 61.
Dans la leçon précédente, nous avons créé des setters basiques qui assignent simplement des valeurs. Mais cela fait l'impasse sur un avantage clé de l'encapsulation : la possibilité de protéger vos données en ajoutant une logique de validation.
Considérez un Counter qui ne devrait jamais devenir négatif. Sans encapsulation, n'importe qui pourrait écrire c->value = -50 et corrompre l'état. Avec un setter, vous contrôlez quelles valeurs sont autorisées :
// counter.c
void counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return; // Rejeter silencieusement les entrées non valides
}
c->value = new_value;
}Maintenant, les valeurs négatives sont simplement ignorées.
Vous pourriez également choisir de renvoyer un code d'état pour indiquer le succès ou l'échec :
int counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return 0; // Échec
}
c->value = new_value;
return 1; // Succès
}Ce modèle permet à l'appelant de savoir si l'opération a réussi. L'idée clé est que les setters ne servent pas uniquement à l'affectation — ce sont des gardiens qui imposent des règles sur ce que peut être l'état de votre objet. C'est là le véritable pouvoir de l'encapsulation : votre objet maintient sa propre intégrité, peu importe ce que le code externe tente de faire.
Défi
FacileConstruisons un module Temperature qui protège ses données en utilisant la validation dans le setter. Vous allez créer un suivi de température qui n'accepte que des valeurs comprises dans une plage valide, démontrant ainsi comment les setters agissent comme des gardiens pour l'état de votre objet.
Vous allez créer trois fichiers :
temperature.h: Votre interface publique utilisant le modèle du pointeur opaque. Déclarez un typeTemperatureavec une déclaration anticipée (forward declaration) uniquement. Déclarez ces fonctions :create_temperature— prend un entier pour les degrés initiaux et retourne un pointeur Temperaturefree_temperature— libère la mémoire allouéetemp_get_degrees— getter qui retourne la valeur actuelle de la températuretemp_set_degrees— setter qui retourne unint(1 pour le succès, 0 pour l'échec)
TEMPERATURE_H.temperature.c: Définissez la structure réellestruct Temperatureavec un membreint degreescaché. Implémentez toutes les fonctions. La clé est votre setter — il ne doit accepter que des valeurs comprises entre -50 et 150 (inclus). Si la valeur est en dehors de cette plage, retournez 0 et laissez la température inchangée. Si elle est valide, mettez à jour la valeur et retournez 1.main.c: Démontrez la validation en essayant de définir des températures valides et invalides, montrant que les valeurs invalides sont rejetées tandis que les valeurs valides sont acceptées.
Vous recevrez trois entrées : la température initiale, une température valide à définir (dans la plage), et une température invalide à tenter (hors de la plage).
Dans votre fichier principal, créez une Temperature avec la valeur initiale et affichez-la. Essayez ensuite de définir la température invalide — comme elle doit être rejetée, affichez le résultat et montrez que la valeur reste inchangée. Enfin, définissez la température valide, affichez le résultat de succès et montrez la valeur mise à jour. Libérez la mémoire et confirmez le nettoyage.
Affichez la sortie dans ce format :
Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
FreedPar exemple, avec les entrées 25, 100, et 200, la sortie serait :
Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
FreedCela démontre le véritable pouvoir de l'encapsulation — votre setter applique les règles sur ce qui constitue une température valide, protégeant l'intégrité de l'objet quelles que soient les valeurs que le code externe tente d'assigner.
Aide-mémoire
Les setters peuvent inclure une logique de validation pour protéger l'intégrité des données. Au lieu de simplement assigner des valeurs, ils agissent comme des gardiens qui imposent des règles sur les états valides des objets.
Exemple de validation de base - rejet silencieux d'une entrée invalide :
void counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return; // Reject invalid input
}
c->value = new_value;
}Retourner un code d'état pour indiquer le succès ou l'échec :
int counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return 0; // Failure
}
c->value = new_value;
return 1; // Success
}Ce modèle permet aux appelants de vérifier si l'opération a réussi, permettant ainsi aux objets de maintenir leur propre intégrité indépendamment des tentatives du code externe.
Essayez vous-même
#include <stdio.h>
#include "temperature.h"
int main() {
// Lire les entrées
int initial, valid_temp, invalid_temp;
scanf("%d", &initial);
scanf("%d", &valid_temp);
scanf("%d", &invalid_temp);
// TODO: Créer une Temperature avec la valeur initiale
// TODO: Afficher la température initiale
// Format: "Initial: {degrees}"
// TODO: Tenter de définir la température invalide
// Afficher le résultat et montrer que la valeur reste inchangée
// Format: "Set {invalid}: {0 or 1}"
// Format: "After invalid: {degrees}"
// TODO: Définir la température valide
// Afficher le résultat de succès et montrer la valeur mise à jour
// Format: "Set {valid}: {0 or 1}"
// Format: "After valid: {degrees}"
// TODO: Libérer la mémoire et afficher "Freed"
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Object Oriented Programming
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercle