Ich habe ein Projekt, bei dem ich eine ganze Menge Konfigurationsdaten erstellen muss, bevor ich einen Prozess ausführen kann. Während der Konfigurationsphase ist es sehr praktisch, die Daten als änderbar zu haben. Sobald die Konfiguration abgeschlossen ist, möchte ich jedoch eine unveränderliche Ansicht dieser Daten an den funktionalen Prozess übergeben, da dieser Prozess für viele seiner Berechnungen auf die Konfigurationsunveränderlichkeit angewiesen ist (z. B. die Möglichkeit, Dinge auf der Basis von Berechnungen vorab zu berechnen) Bei der anfänglichen Konfiguration.) Ich habe eine mögliche Lösung mit Hilfe von Schnittstellen gefunden, um eine schreibgeschützte Ansicht verfügbar zu machen, aber ich würde gerne wissen, ob jemand Probleme mit dieser Art von Ansatz gehabt hat oder ob es andere Empfehlungen dafür gibt löse dieses Problem.
Ein Beispiel für das Muster, das ich gerade verwende:
%Vor%BEARBEITEN
Basierend auf den Eingaben von Mr. Lippert und cdhowie, habe ich folgendes zusammengestellt (einige Eigenschaften wurden entfernt, um zu vereinfachen):
%Vor% FreezableList<T>
ist, wie zu erwarten, eine Freezable-Implementierung von IList<T>
. Dies bringt Vorteile bei der Isolierung, auf Kosten einer zusätzlichen Komplexität.
Der Ansatz, den Sie beschreiben, funktioniert gut, wenn der "Client" (der Konsument der Schnittstelle) und der "Server" (der Anbieter der Klasse) eine gegenseitige Übereinstimmung haben, dass:
Wenn Sie zwischen den Leuten, die den Client schreiben, und den Leuten, die den Server schreiben, keine gute Arbeitsbeziehung haben, dann gehen die Dinge schnell in Birnenform. Ein unhöflicher Klient kann natürlich die Unveränderlichkeit wegwerfen, indem er auf den öffentlichen Konfigurationstyp überträgt. Ein unhöflicher Server kann eine unveränderliche Ansicht ausgeben und das Objekt dann mutieren, wenn der Client es am wenigsten erwartet.
Ein netter Ansatz besteht darin, zu verhindern, dass der Client den veränderbaren Typ jemals sieht:
%Vor%Wenn Sie nun einen Frobber erstellen und mutieren wollen, können Sie einen Frobber.FrobBuilder erstellen. Wenn Sie Ihre Mutationen erledigt haben, rufen Sie Complete auf und erhalten eine schreibgeschützte Schnittstelle. (Und dann wird der Builder ungültig.) Da alle Mutationsimplementierungsdetails in einer privaten verschachtelten Klasse verborgen sind, können Sie die IReadOnly-Schnittstelle nicht zu RealFrobber "wegwerfen", sondern nur zu Frobber, der keine öffentlichen Methoden hat!
>Auch kann der feindliche Client keinen eigenen Frobber erstellen, weil Frobber abstrakt ist und einen privaten Konstruktor hat. Die einzige Möglichkeit, einen Frobber zu machen, ist der Builder.
Dies funktioniert, aber "böswillige" Methoden versuchen möglicherweise, IConfiguration
auf Configuration
zu transformieren und damit die Beschränkungen zu umgehen, die durch die Schnittstelle verursacht werden. Wenn Sie sich darüber keine Sorgen machen, wird Ihr Ansatz gut funktionieren.
Normalerweise mache ich so etwas:
%Vor%Alternativ könnten Sie Ihre veränderbaren Klassen in unveränderbare Klassen einbetten.
Ich arbeite regelmäßig mit einem großen, COM-basierten Framework (ArcGIS Engine von ESRI), das Änderungen in einigen Situationen sehr ähnlich behandelt: Es gibt die "default" IFoo
-Schnittstellen für schreibgeschützten Zugriff und IFooEdit
Schnittstellen (falls zutreffend) für Änderungen.
Dieser Rahmen ist ziemlich bekannt, und mir sind keine verbreiteten Beschwerden über diese bestimmte Designentscheidung bekannt.
Schließlich denke ich, dass es definitiv einen zusätzlichen Gedanken wert ist, zu entscheiden, welche "Perspektive" die Standardansicht wird: die schreibgeschützte Perspektive oder die Vollzugriffsansicht. Ich würde die schreibgeschützte Ansicht als Standard festlegen.
Wie wäre es mit:
%Vor%Ich habe es Readonly genannt, aber ich bin mir nicht sicher, ob das der beste Name dafür ist.
Tags und Links mutability .net c# interface immutability