Muster für Unveränderlichkeit
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 34 von 70.
Unveränderlichkeit (Immutability) führt die Kapselung zu ihrem logischen Extrem – sobald ein Objekt erstellt wurde, kann es sich nie mehr ändern. Dies eliminiert ganze Kategorien von Fehlern, da man sich nie Sorgen machen muss, dass etwas die Daten unerwartet ändert.
Der einfachste Weg, eine unveränderliche Klasse zu erstellen, besteht darin, readonly-Felder mit einem Konstruktor zu verwenden, der alle Werte setzt, und keine Setter bereitzustellen:
public class Point
{
public readonly int X;
public readonly int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
}Sobald ein Point erstellt wurde, können seine Koordinaten nicht mehr geändert werden. Aber was ist, wenn Sie eine modifizierte Version benötigen? Anstatt das bestehende Objekt zu ändern, geben Sie ein neues zurück:
public Point Move(int deltaX, int deltaY)
{
return new Point(X + deltaX, Y + deltaY);
}Der ursprüngliche Punkt bleibt unverändert, während Sie einen neuen Punkt mit aktualisierten Werten erhalten. Dieses Muster wird in ganz .NET verwendet – Strings zum Beispiel sind unveränderlich. Wenn Sie ToUpper() aufrufen, erhalten Sie einen neuen String, anstatt den ursprünglichen zu ändern.
Unveränderliche Objekte sind von Natur aus threadsicher, da kein Code sie nach der Erstellung ändern kann. Sie sind zudem einfacher nachzuvollziehen, da man weiß, dass sich ihr Zustand niemals unerwartet ändern wird.
Aufgabe
EinfachErstellen wir ein unveränderliches Geldsystem, das demonstriert, wie Objekte so entworfen werden können, dass sie sich nach ihrer Erstellung niemals ändern. Du erstellst eine Money-Klasse, bei der jede Operation ein neues Objekt zurückgibt, anstatt das ursprüngliche zu verändern – ein Muster, das deinen Code sicherer und leichter nachvollziehbar macht.
Du organisierst deinen Code über zwei Dateien:
Money.cs: Erstelle eine unveränderlicheMoney-Klasse imFinance-Namespace. Dein Geldobjekt sollte Folgendes haben:- Zwei
readonly-Felder:Amount(decimal) undCurrency(string) - Einen Konstruktor, der beide Werte festlegt – sobald ein Money-Objekt erstellt wurde, kann es sich niemals ändern
- Eine Methode
Add(decimal value), die ein neuesMoney-Objekt mit dem erhöhten Betrag zurückgibt (gleiche Währung) - Eine Methode
Subtract(decimal value), die ein neuesMoney-Objekt mit dem verringerten Betrag zurückgibt (gleiche Währung) - Eine Methode
Convert(string newCurrency, decimal rate), die ein neuesMoney-Objekt zurückgibt, dessen Betrag mit dem Kurs multipliziert wurde und das die neue Währung verwendet - Eine Methode
GetDisplay(), die einen String im Format"{Amount} {Currency}"zurückgibt
Money-Instanzen zurück!- Zwei
Program.cs: Demonstriere in deiner Hauptdatei die Unveränderlichkeit in Aktion. Erstelle zunächst einMoney-Objekt und führe dann Operationen darauf aus, während du Verweise sowohl auf das ursprüngliche Objekt als auch auf die Ergebnisse behältst. Dadurch wird bewiesen, dass sich das ursprüngliche Objekt auch nach mehreren Operationen niemals ändert.
Du erhältst vier Eingaben:
- Anfangsbetrag (decimal)
- Anfangswährung (string)
- Hinzuzufügender Betrag (decimal)
- Umrechnungskurs in EUR (decimal)
Gib die Ausgabe in diesem Format aus:
Original: {GetDisplay()}
After add: {GetDisplay()}
Original unchanged: {GetDisplay()}
Converted: {GetDisplay()}Wenn die Eingaben beispielsweise 100.00, USD, 50.00 und 0.85 lauten, sollte die Ausgabe folgendermaßen aussehen:
Original: 100.00 USD
After add: 150.00 USD
Original unchanged: 100.00 USD
Converted: 127.50 EURBeachte, dass das ursprüngliche Money-Objekt auch nach dem Aufruf von 100.00 USD weiterhin Add() anzeigt – das ist Unveränderlichkeit! Die Methode Add() hat ein vollständig neues Objekt mit 150.00 USD erstellt und das ursprüngliche Objekt unverändert gelassen. Die Umrechnung wird am Ergebnis der Additionsoperation durchgeführt.
Probier es selbst
using System;
using Finance;
class Program
{
public static void Main(string[] args)
{
// Eingaben lesen
decimal initialAmount = Convert.ToDecimal(Console.ReadLine());
string initialCurrency = Console.ReadLine();
decimal amountToAdd = Convert.ToDecimal(Console.ReadLine());
decimal conversionRate = Convert.ToDecimal(Console.ReadLine());
// TODO: Erstelle ein initiales Money-Objekt mit dem ursprünglichen Betrag und der Währung
// TODO: Gib das ursprüngliche Geld mit GetDisplay() aus
// TODO: Rufe Add() auf dem Original auf und speichere das Ergebnis in einer neuen Variable
// TODO: Gib das Ergebnis nach dem Hinzufügen mit GetDisplay() aus
// TODO: Gib das Original erneut aus, um zu beweisen, dass es unverändert ist
// TODO: Konvertiere das addierte Ergebnis unter Verwendung des Wechselkurses in EUR
// TODO: Gib das konvertierte Geld mit GetDisplay() aus
}
}
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 OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler