Unveränderliches Objektmuster in C # - was denkst du?

Habe ich im Laufe von ein paar Projekten entwickelt ein Muster für die Erstellung unveränderlich (readonly) - Objekte und unveränderliche Objekt-Graphen. Unveränderliche Objekte tragen den Vorteil, dass Sie 100% thread-safe und kann daher wiederverwendet werden mehrere threads. In meiner Arbeit habe ich sehr oft verwenden diese Muster in Web-Anwendungen für Konfiguration, Einstellungen und andere Objekte, die ich laden und cache im Arbeitsspeicher. Zwischengespeicherte Objekte sollten immer unveränderlich sind, wie Sie gewährleisten wollen, sind Sie nicht unerwartet verändert.

Nun, Sie können natürlich leicht design immutable Objekte, wie im folgenden Beispiel:

public class SampleElement
{
  private Guid id;
  private string name;

  public SampleElement(Guid id, string name)
  {
    this.id = id;
    this.name = name;
  }

  public Guid Id
  {
    get { return id; }
  }

  public string Name
  {
    get { return name; }
  }
}

Dies ist in Ordnung für einfache Klassen - aber für komplexere Klassen ich Bilde mir nicht ein das Konzept, indem alle Werte durch einen Konstruktor. Mit Set-Methoden auf die Eigenschaften ist wünschenswert und Ihr code wird mit dem Bau eines neuen Objekts wird leichter zu Lesen.

Wie erstellen Sie also unveränderliche Objekte mit setter?

Gut, in meiner pattern-Objekte von Anfang an so vollständig verändert, bis Sie frieren Sie mit einem einzigen Methodenaufruf. Sobald ein Objekt fixiert wird, dann bleibt unveränderlich für immer - es kann nicht sein, verwandelte sich in ein veränderliches Objekt wieder. Wenn Sie eine veränderliche version des Objekts, die Sie einfach zu Klonen.

Ok, nun zum code. Ich habe im folgenden code-Schnipsel versucht zu Kochen, das Muster nach unten auf seine einfachste form. Die IElement ist die Basis-Schnittstelle, die alle unveränderlichen Objekte müssen schließlich umsetzen.

public interface IElement : ICloneable
{
  bool IsReadOnly { get; }
  void MakeReadOnly();
}

Die Element-Klasse ist die default-Implementierung des interface IElement:

public abstract class Element : IElement
{
  private bool immutable;

  public bool IsReadOnly
  {
    get { return immutable; }
  }

  public virtual void MakeReadOnly()
  {
    immutable = true;
  }

  protected virtual void FailIfImmutable()
  {
    if (immutable) throw new ImmutableElementException(this);
  }

  ...
}

Let ' s umgestalten der SampleElement Klasse zu implementieren, das immutable-Objekt-Muster:

public class SampleElement : Element
{
  private Guid id;
  private string name;

  public SampleElement() {}

  public Guid Id
  {
    get 
    { 
      return id; 
    }
    set
    {
      FailIfImmutable();
      id = value;
    }
  }

  public string Name
  {
    get 
    { 
      return name; 
    }
    set
    {
      FailIfImmutable();
      name = value;
    }
  }
}

Können Sie nun ändern Sie die Id-Eigenschaft und die Name-Eigenschaft, solange das Objekt noch nicht markiert wurden, als unveränderliche, durch aufrufen der MakeReadOnly () - Methode. Einmal ist es unveränderlich, Aufruf einer setter-Ausbeute wird eine ImmutableElementException.

Letzte Anmerkung:
Das vollständige Muster ist komplexer als der code-Schnipsel, die hier gezeigt werden. Es enthält auch Unterstützung für Sammlungen von immutable Objekte und kompletter Objekt-Graphen unveränderliche Objekt-Graphen. Der auf das komplette Suchmuster können Sie ein ganzes Objekt graph unveränderlich durch aufrufen der MakeReadOnly () - Methode für das äußere object. Sobald Sie beginnen, die Erstellung von größeren Objekt-Modelle mit diesem Muster das Risiko von undichten Objekte erhöht. Ein leaky-Objekt ist ein Objekt, das nicht rufen Sie die FailIfImmutable () - Methode auf, bevor eine änderung am Objekt. Zum testen auf Undichtigkeiten habe ich auch entwickelt eine generische Leck-Detektor-Klasse für die Verwendung in unit-tests. Es verwendet reflektion, um zu testen, ob alle Eigenschaften und Methoden werfen die ImmutableElementException in der unveränderlichen Zustand.
In anderen Worten TDD verwendet wird, hier.

Ich habe zugenommen, wie dieses Muster eine Menge und finden Sie tolle Vorteile. Also was ich gerne wissen würde ist, ob jemand von Euch mit ähnlichen mustern? Wenn ja, kennen Sie eine gute Ressourcen, die es zu dokumentieren? Ich bin eigentlich auf der Suche nach möglichen Verbesserungen und für alle Normen, die möglicherweise existieren bereits zu diesem Thema.

InformationsquelleAutor der Frage Lars Fastrup | 2008-11-04

Schreibe einen Kommentar