Menu
CoddyTech

Validación en setters

Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 20 de 61.

En la lección anterior, creamos setters básicos que simplemente asignan valores. Pero esto pasa por alto una ventaja clave de la encapsulación: la capacidad de proteger tus datos añadiendo lógica de validación.

Considera un Counter que nunca debería ser negativo. Sin encapsulación, cualquiera podría escribir c->value = -50 y corromper el estado. Con un setter, controlas qué valores se permiten:

// counter.c
void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // Rechaza silenciosamente la entrada no válida
    }
    c->value = new_value;
}

Ahora los valores negativos simplemente se ignoran.

También podrías optar por devolver un código de estado para indicar si la operación se realizó correctamente o no:

int counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return 0;  // Fallo
    }
    c->value = new_value;
    return 1;  // Éxito
}

Este patrón permite que quien realiza la llamada sepa si la operación se completó correctamente. La idea clave es que los métodos setter no se limitan a asignar valores: son guardianes que hacen cumplir las reglas sobre el estado que puede tener tu objeto. Este es el verdadero poder de la encapsulación: tu objeto mantiene su propia integridad, independientemente de lo que intente hacer el código externo.

challenge icon

Desafío

Fácil

Vamos a crear un módulo Temperature que proteja sus datos mediante validación en el setter. Crearás un rastreador de temperatura que solo acepte valores dentro de un rango válido: así demostrarás cómo los setters actúan como guardianes del estado de tu objeto.

Crearás tres archivos:

  • temperature.h: Tu interfaz pública, que utiliza el patrón de puntero opaco. Declara un tipo Temperature únicamente con una declaración anticipada. Declara estas funciones:
    • create_temperature: recibe un entero para los grados iniciales y devuelve un puntero a Temperature
    • free_temperature: libera la memoria asignada
    • temp_get_degrees: getter que devuelve el valor actual de la temperatura
    • temp_set_degrees: setter que devuelve un int (1 si tiene éxito, 0 si falla)
    Usa protecciones de inclusión con el símbolo TEMPERATURE_H.
  • temperature.c: Define la struct Temperature real con un miembro int degrees oculto. Implementa todas las funciones. La clave está en el setter. Solo debe aceptar valores entre -50 y 150 (inclusive). Si el valor está fuera de este rango, devuelve 0 y deja la temperatura sin cambios. Si es válido, actualiza el valor y devuelve 1.
  • main.c: Demuestra la validación intentando establecer temperaturas válidas e inválidas, y mostrando que los valores inválidos se rechazan mientras que los válidos se aceptan.

Recibirás tres entradas: la temperatura inicial, una temperatura válida para establecer (dentro del rango) y una temperatura inválida para intentar establecer (fuera del rango).

En tu archivo main, crea una Temperature con el valor inicial e imprímela. Luego intenta establecer la temperatura inválida; como debería rechazarse, imprime el resultado y muestra que el valor permanece sin cambios. Por último, establece la temperatura válida, imprime el resultado satisfactorio y muestra el valor actualizado. Libera la memoria y confirma que se ha limpiado.

Imprime la salida con este formato:

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

Por ejemplo, con las entradas 25, 100 y 200, la salida sería:

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

Esto demuestra el verdadero poder de la encapsulación. Tu setter aplica las reglas que determinan qué constituye una temperatura válida y protege la integridad del objeto, independientemente de los valores que el código externo intente asignar.

Pruébalo tú mismo

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

int main() {
    // Lee las entradas
    int initial, valid_temp, invalid_temp;
    scanf("%d", &initial);
    scanf("%d", &valid_temp);
    scanf("%d", &invalid_temp);
    
    // TODO: Crea un Temperature con el valor inicial
    
    // TODO: Imprime la temperatura inicial
    // Formato: "Initial: {degrees}"
    
    // TODO: Intenta establecer la temperatura no válida
    // Imprime el resultado y muestra que el valor permanece sin cambios
    // Formato: "Set {invalid}: {0 or 1}"
    // Formato: "After invalid: {degrees}"
    
    // TODO: Establece la temperatura válida
    // Imprime el resultado de la operación y muestra el valor actualizado
    // Formato: "Set {valid}: {0 or 1}"
    // Formato: "After valid: {degrees}"
    
    // TODO: Libera la memoria e imprime "Freed"
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C online