Validierung in Settern
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 20 von 61.
In der vorherigen Lektion haben wir grundlegende Setter erstellt, die lediglich Werte zuweisen. Dabei bleibt jedoch ein wesentlicher Vorteil der Kapselung ungenutzt: die Möglichkeit, deine Daten zu schützen, indem Validierungslogik hinzugefügt wird.
Stell dir einen Counter vor, der niemals negativ werden sollte. Ohne Kapselung könnte jeder c->value = -50 schreiben und den Zustand beschädigen. Mit einem Setter kontrollierst du, welche Werte zulässig sind:
// counter.c
void counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return; // Ungültige Eingabe stillschweigend ablehnen
}
c->value = new_value;
}Jetzt werden negative Werte einfach ignoriert.
Du könntest dich auch dafür entscheiden, einen Statuscode zurückzugeben, um Erfolg oder Fehlschlag anzuzeigen:
int counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return 0; // Fehlschlag
}
c->value = new_value;
return 1; // Erfolg
}Dieses Muster lässt den Aufrufer wissen, ob der Vorgang erfolgreich war. Die zentrale Erkenntnis ist, dass Setter nicht nur der Zuweisung dienen: Sie sind Wächter, die Regeln darüber durchsetzen, wie der Zustand deines Objekts aussehen darf. Das ist die wahre Stärke der Kapselung: Dein Objekt bewahrt seine eigene Integrität, unabhängig davon, was externer Code zu tun versucht.
Aufgabe
EinfachLass uns ein Temperature-Modul erstellen, das seine Daten mithilfe einer Validierung im Setter schützt. Du erstellst einen Temperatur-Tracker, der nur Werte innerhalb eines gültigen Bereichs akzeptiert: So wird demonstriert, wie Setter als Torwächter für den Zustand deines Objekts fungieren.
Du erstellst drei Dateien:
temperature.h: Deine öffentliche Schnittstelle unter Verwendung des Musters für opake Zeiger. Deklariere einen TypTemperatureausschließlich mit einer Vorwärtsdeklaration. Deklariere diese Funktionen:create_temperature: nimmt eine Ganzzahl für die Anfangstemperatur entgegen und gibt einen Temperature-Zeiger zurückfree_temperature: gibt den reservierten Speicher freitemp_get_degrees: Getter, der den aktuellen Temperaturwert zurückgibttemp_set_degrees: Setter, der einintzurückgibt (1 für Erfolg, 0 für Misserfolg)
TEMPERATURE_H.temperature.c: Definiere die tatsächlichestruct Temperaturemit einem verborgenenint degrees-Member. Implementiere alle Funktionen. Der entscheidende Punkt ist dein Setter. Er sollte nur Werte zwischen -50 und 150 (einschließlich) akzeptieren. Liegt der Wert außerhalb dieses Bereichs, gib 0 zurück und lasse die Temperatur unverändert. Ist der Wert gültig, aktualisiere den Wert und gib 1 zurück.main.c: Demonstriere die Validierung, indem du versuchst, sowohl gültige als auch ungültige Temperaturen zu setzen, und zeige dabei, dass ungültige Werte abgelehnt werden, während gültige Werte akzeptiert werden.
Du erhältst drei Eingaben: die Anfangstemperatur, eine zu setzende gültige Temperatur (innerhalb des Bereichs) und eine zu versuchende ungültige Temperatur (außerhalb des Bereichs).
Erstelle in deiner main-Datei eine Temperature mit dem Anfangswert und gib sie aus. Versuche dann, die ungültige Temperatur zu setzen, da sie abgelehnt werden sollte, gib das Ergebnis aus und zeige, dass der Wert unverändert bleibt. Setze schließlich die gültige Temperatur, gib das Erfolgsergebnis aus und zeige den aktualisierten Wert. Gib den Speicher frei und bestätige die Bereinigung.
Gib die Ausgabe in diesem Format aus:
Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
FreedBeispielsweise würde die Ausgabe bei den Eingaben 25, 100 und 200 wie folgt aussehen:
Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
FreedDies demonstriert die wahre Stärke der Kapselung. Dein Setter erzwingt die Regeln dafür, was eine gültige Temperatur ausmacht, und schützt die Integrität des Objekts unabhängig davon, welche Werte externer Code zuzuweisen versucht.
Probier es selbst
#include <stdio.h>
#include "temperature.h"
int main() {
// Eingaben lesen
int initial, valid_temp, invalid_temp;
scanf("%d", &initial);
scanf("%d", &valid_temp);
scanf("%d", &invalid_temp);
// TODO: Erstelle ein Temperature mit dem Anfangswert
// TODO: Gib die Anfangstemperatur aus
// Format: "Initial: {degrees}"
// TODO: Versuche, die ungültige Temperatur zu setzen
// Gib das Ergebnis aus und zeige, dass der Wert unverändert bleibt
// Format: "Set {invalid}: {0 or 1}"
// Format: "After invalid: {degrees}"
// TODO: Setze die gültige Temperatur
// Gib das Erfolgsergebnis aus und zeige den aktualisierten Wert
// Format: "Set {valid}: {0 or 1}"
// Format: "After valid: {degrees}"
// TODO: Gib den Speicher frei und gib "Freed" aus
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der modularen Programmierung
Header-DateienInclude GuardsQuelldateienStatische FunktionenWiederholung: Modularer Taschenrechner4Kapselung
Konzept der Opaque PointersOpaque Structs definierenGetter und SetterValidierung in SetternRückblick: Die geheime Box2Objekte und Methoden
Structs als ObjekteDer 'Self'-PointerConst-CorrectnessPointer vs. WertHilfsmethodenZusammenfassung: Point Manager5Projekt: Einfaches Bankkonto
Projekt-SetupImplementierung des Kontos3Objekt-Lebenszyklus
Konstruktor-MusterDestruktor-MusterStack-InitialisierungTiefe KopieRückblick: String-Wrapper6Vererbung durch Komposition
Struct-EinbettungDie First-Member-RegelZugriff auf Parent-MemberUpcastingRückblick: Formenhierarchie9Projekt: Formen-Zeichner
ProjektübersichtKreis-ImplementierungRechteck-ImplementierungPolymorphe VerwendungShape-ContainerÜbe selbstständig: Online-C-Compiler