Menu
CoddyTech

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 kluczową zaletę enkapsulacji: możliwość ochrony danych przez dodanie logiki walidacji.

Rozważ Counter, który nigdy nie powinien przyjmować wartości ujemnych. Bez hermetyzacji każdy mógłby napisać c->value = -50 i naruszyć 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 także 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;  // Powodzenie
}

Ten wzorzec pozwala wywołującemu sprawdzić, czy operacja się powiodła. 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 Twojego obiektu. Na tym polega prawdziwa siła enkapsulacji: obiekt zachowuje własną integralność, niezależnie od tego, co próbuje zrobić zewnętrzny kod.

challenge icon

Wyzwanie

Łatwy

Zbudujmy moduł Temperature, który chroni swoje dane, stosując walidację w setterze. Utworzysz moduł śledzący temperaturę, który akceptuje tylko wartości z prawidłowego zakresu — pokażemy, jak settery pełnią rolę strażników stanu obiektu.

Utworzysz trzy pliki:

  • temperature.h: publiczny interfejs wykorzystujący wzorzec nieprzezroczystego wskaźnika. Zadeklaruj typ Temperature wyłącznie przez deklarację wstępną. Zadeklaruj następujące funkcje:
    • create_temperature: przyjmuje liczbę całkowitą oznaczającą początkową temperaturę 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ć wyłącznie wartości z zakresu od -50 do 150 (włącznie). Jeśli wartość wykracza poza ten zakres, zwróć 0 i pozostaw temperaturę bez zmian. Jeśli jest prawidłowa, zaktualizuj wartość i zwróć 1.
  • main.c: Zademonstruj walidację, próbując ustawić zarówno prawidłowe, jak i nieprawidłowe temperatury, i pokaż, że nieprawidłowe wartości są odrzucane, a prawidłowe akceptowane.

Otrzymasz trzy wartości wejściowe: temperaturę początkową, prawidłową temperaturę do ustawienia (z zakresu) oraz nieprawidłową temperaturę, której ustawienia należy spróbować (spoza zakresu).

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

Wyświetl 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 byłby następujący:

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

To pokazuje prawdziwą siłę hermetyzacji. Twój 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ć do niego kod zewnętrzny.

Spróbuj swoich sił

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

int main() {
    // Odczytaj 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