Menu
Coddy logo textTech

Validation dans les setters

Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 20 sur 61.

Dans la leçon précédente, nous avons créé des setters basiques qui attribuent simplement des valeurs. Mais cela ne tient pas compte d’un avantage essentiel 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 les valeurs autorisées :

// counter.c
void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // Rejeter silencieusement les entrées invalides
    }
    c->value = new_value;
}

Désormais, les valeurs négatives sont simplement ignorées.

Vous pouvez é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 essentielle est que les setters ne servent pas uniquement à effectuer une affectation : ce sont des gardiens qui imposent des règles concernant l'état que votre objet peut avoir. C'est là le véritable pouvoir de l'encapsulation : votre objet préserve sa propre intégrité, quelles que soient les actions tentées par du code externe.

challenge icon

Défi

Facile

Construisons un module Temperature qui protège ses données grâce à une validation dans le setter. Vous créerez un outil de suivi de la température qui n'accepte que les valeurs comprises dans une plage valide : cela montre comment les setters jouent le rôle de gardiens de 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 type Temperature avec uniquement une déclaration anticipée. Déclarez ces fonctions :
    • create_temperature : prend un entier pour les degrés initiaux et renvoie un pointeur vers Temperature
    • free_temperature : libère la mémoire allouée
    • temp_get_degrees : getter qui renvoie la valeur actuelle de la température
    • temp_set_degrees : setter qui renvoie un int (1 en cas de réussite, 0 en cas d'échec)
    Utilisez des gardes d'inclusion avec le symbole TEMPERATURE_H.
  • temperature.c : définissez la véritable struct Temperature avec un membre int degrees caché. Implémentez toutes les fonctions. L'élément essentiel est votre setter. Il ne doit accepter que les valeurs comprises entre -50 et 150 (inclus). Si la valeur est en dehors de cette plage, renvoyez 0 et laissez la température inchangée. Si elle est valide, mettez à jour la valeur et renvoyez 1.
  • main.c : démontrez la validation en essayant de définir des températures valides et invalides, afin de montrer 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 à essayer (en dehors de la plage).

Dans votre fichier main, créez une Temperature avec la valeur initiale et affichez-la. Essayez ensuite de définir la température invalide, puisqu'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 la réussite 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}
Freed

Par 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
Freed

Cela démontre la véritable puissance de l'encapsulation. Votre setter applique les règles définissant ce qui constitue une température valide, protégeant ainsi l'intégrité de l'objet quelles que soient les valeurs que le code externe tente d'assigner.

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 un 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;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur C en ligne