Menu
Coddy logo textTech

Walidacja w setterach

Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 20 z 61.

W poprzedniej lekcji utworzyliśmy podstawowe funkcje ustawiające, które po prostu przypisują wartości. Pomija to jednak ważną zaletę enkapsulacji: możliwość ochrony danych przez dodanie logiki walidacji.

Rozważmy Counter, który nigdy nie powinien przyjmować wartości ujemnych. Bez enkapsulacji każdy mógłby napisać c->value = -50 i uszkodzić stan. Dzięki metodzie ustawiającej kontrolujesz, jakie wartości są dozwolone:

// counter.c
void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // Odrzuć nieprawidłowe dane wejściowe bez komunikatu
    }
    c->value = new_value;
}

Teraz wartości ujemne są po prostu ignorowane.

Możesz też zdecydować się zwrócić kod statusu, aby wskazać powodzenie lub niepowodzenie:

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

Ten wzorzec pozwala wywołującemu dowiedzieć się, czy operacja zakończyła się powodzeniem. Kluczowy wniosek jest taki, że settery nie służą wyłącznie do przypisywania wartości: są strażnikami, którzy egzekwują zasady dotyczące tego, jaki może być stan obiektu. Na tym polega prawdziwa siła enkapsulacji: obiekt zachowuje swoją integralność, niezależnie od tego, co próbuje zrobić zewnętrzny kod.

challenge icon

Wyzwanie

Łatwy

Zbudujmy moduł Temperature, który chroni swoje dane, sprawdzając je w setterze. Utworzysz rejestrator temperatury, który akceptuje tylko wartości z prawidłowego zakresu — pokażemy, jak settery pilnują stanu obiektu.

Utworzysz trzy pliki:

  • temperature.h: publiczny interfejs wykorzystujący wzorzec nieprzezroczystego wskaźnika. Zadeklaruj typ Temperature wyłącznie za pomocą deklaracji wstępnej. Zadeklaruj następujące funkcje:
    • create_temperature: przyjmuje liczbę całkowitą oznaczającą temperaturę początkową i zwraca wskaźnik do Temperature
    • free_temperature: zwalnia przydzieloną pamięć
    • temp_get_degrees: getter zwracający bieżącą wartość temperatury
    • temp_set_degrees: setter zwracający int (1 w przypadku powodzenia, 0 w przypadku niepowodzenia)
    Użyj strażników dołączania z symbolem TEMPERATURE_H.
  • temperature.c: Zdefiniuj właściwą strukturę struct Temperature z ukrytym polem int degrees. Zaimplementuj wszystkie funkcje. Kluczowy jest setter. Powinien akceptować tylko wartości z zakresu od -50 do 150 (włącznie). Jeśli wartość jest poza tym zakresem, zwróć 0 i pozostaw temperaturę bez zmian. Jeśli wartość jest prawidłowa, zaktualizuj ją i zwróć 1.
  • main.c: Pokaż działanie walidacji, próbując ustawić zarówno prawidłowe, jak i nieprawidłowe temperatury, aby wykazać, że nieprawidłowe wartości są odrzucane, a prawidłowe akceptowane.

Otrzymasz trzy dane wejściowe: temperaturę początkową, prawidłową temperaturę do ustawienia (z zakresu) oraz nieprawidłową temperaturę do sprawdzenia (spoza zakresu).

W pliku głównym utwórz Temperature z początkową wartością i ją wypisz. Następnie spróbuj ustawić nieprawidłową temperaturę, a ponieważ powinna zostać odrzucona, wypisz wynik i pokaż, że wartość pozostała bez zmian. Na koniec ustaw prawidłową temperaturę, wypisz informację o powodzeniu i pokaż zaktualizowaną wartość. Zwolnij pamięć i potwierdź sprzątanie.

Wypisz wynik w tym formacie:

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

Na przykład dla danych wejściowych 25, 100 i 200 wynik wyglądałby tak:

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

To pokazuje prawdziwą moc hermetyzacji. Setter egzekwuje zasady określające, jaka temperatura jest prawidłowa, chroniąc integralność obiektu niezależnie od tego, jakie wartości próbuje przypisać kod zewnętrzny.

Spróbuj swoich sił

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

int main() {
    // Wczytaj dane wejściowe
    int initial, valid_temp, invalid_temp;
    scanf("%d", &initial);
    scanf("%d", &valid_temp);
    scanf("%d", &invalid_temp);
    
    // TODO: Utwórz obiekt Temperature z wartością początkową
    
    // TODO: Wypisz temperaturę początkową
    // Format: "Initial: {degrees}"
    
    // TODO: Spróbuj ustawić nieprawidłową temperaturę
    // Wypisz wynik i pokaż, że wartość pozostała bez zmian
    // Format: "Set {invalid}: {0 or 1}"
    // Format: "After invalid: {degrees}"
    
    // TODO: Ustaw prawidłową temperaturę
    // Wypisz wynik operacji i pokaż zaktualizowaną wartość
    // Format: "Set {valid}: {0 or 1}"
    // Format: "After valid: {degrees}"
    
    // TODO: Zwolnij pamięć i wypisz "Freed"
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C online