Validierung in Settern
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 20 von 61.
In der vorherigen Lektion haben wir einfache Setter erstellt, die lediglich Werte zuweisen. Dabei geht jedoch ein entscheidender Vorteil der Kapselung verloren: die Möglichkeit, deine Daten durch das Hinzufügen von Validierungslogik zu schützen.
Betrachten wir einen Counter, der niemals negativ werden soll. 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 ohne Meldung zurückweisen
}
c->value = new_value;
}Negative Werte werden jetzt einfach ignoriert.
Du kannst dich auch dafür entscheiden, einen Statuscode zurückzugeben, um Erfolg oder Misserfolg 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 entscheidende Erkenntnis ist, dass Setter nicht nur der Zuweisung dienen: Sie sind Wächter, die Regeln dafür durchsetzen, welchen Zustand dein Objekt haben kann. Das ist die wahre Stärke der Kapselung: Dein Objekt bewahrt seine eigene Integrität, unabhängig davon, was externer Code 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 gezeigt, wie Setter als Wächter für den Zustand deines Objekts fungieren.
Du erstellst drei Dateien:
temperature.h: Deine öffentliche Schnittstelle mit dem Muster des opaken Zeigers. 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 zugewiesenen Speicher freitemp_get_degrees: Getter, der den aktuellen Temperaturwert zurückgibttemp_set_degrees: Setter, der einenintzurückgibt (1 bei Erfolg, 0 bei Fehlschlag)
TEMPERATURE_H.temperature.c: Definiere das tatsächlichestruct Temperaturemit einem verborgenen Elementint degrees. Implementiere alle Funktionen. Entscheidend 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 ihn und gib 1 zurück.main.c: Veranschauliche die Validierung, indem du versuchst, sowohl gültige als auch ungültige Temperaturen zu setzen, und zeige, dass ungültige Werte abgelehnt und gültige 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 Hauptdatei ein Temperature mit dem Anfangswert und gib ihn 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
FreedDas zeigt die wahre Stärke der Kapselung. Dein Setter setzt die Regeln dafür durch, was als gültige Temperatur gilt, 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 einlesen
int initial, valid_temp, invalid_temp;
scanf("%d", &initial);
scanf("%d", &valid_temp);
scanf("%d", &invalid_temp);
// TODO: Eine Temperature mit dem Anfangswert erstellen
// TODO: Anfangstemperatur ausgeben
// Format: "Initial: {degrees}"
// TODO: Versuchen, die ungültige Temperatur zu setzen
// Das Ergebnis ausgeben und zeigen, dass der Wert unverändert bleibt
// Format: "Set {invalid}: {0 or 1}"
// Format: "After invalid: {degrees}"
// TODO: Die gültige Temperatur setzen
// Das Erfolgsergebnis ausgeben und den aktualisierten Wert anzeigen
// Format: "Set {valid}: {0 or 1}"
// Format: "After valid: {degrees}"
// TODO: Den Speicher freigeben und "Freed" ausgeben
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