Üblicherweise haben Domänenobjekte Eigenschaften, die durch einen integrierten Typ dargestellt werden können, deren gültige Werte jedoch eine Teilmenge der Werte sind, die durch diesen Typ dargestellt werden können.
In diesen Fällen kann der Wert mit dem integrierten Typ gespeichert werden. Es muss jedoch sichergestellt werden, dass die Werte immer am Eingangspunkt validiert werden, da wir sonst möglicherweise mit einem ungültigen Wert arbeiten.
Eine Möglichkeit, dies zu lösen, besteht darin, den Wert als benutzerdefinierten Wert zu speichern, der struct
über ein einzelnes private readonly
Sicherungsfeld des integrierten Typs verfügt und dessen Konstruktor den angegebenen Wert überprüft. Wir können dann immer sicher sein, nur validierte Werte zu verwenden, wenn wir diesen struct
Typ verwenden.
Wir können auch Cast-Operatoren von und zu dem zugrunde liegenden integrierten Typ bereitstellen, damit Werte nahtlos als zugrunde liegender Typ eingegeben und beendet werden können.
Nehmen Sie als Beispiel eine Situation, in der wir den Namen eines Domänenobjekts darstellen müssen und gültige Werte alle Zeichenfolgen sind, deren Länge zwischen 1 und 255 Zeichen liegt. Wir könnten dies mit der folgenden Struktur darstellen:
public struct ValidatedName : IEquatable<ValidatedName>
{
private readonly string _value;
private ValidatedName(string name)
{
_value = name;
}
public static bool IsValid(string name)
{
return !String.IsNullOrEmpty(name) && name.Length <= 255;
}
public bool Equals(ValidatedName other)
{
return _value == other._value;
}
public override bool Equals(object obj)
{
if (obj is ValidatedName)
{
return Equals((ValidatedName)obj);
}
return false;
}
public static implicit operator string(ValidatedName x)
{
return x.ToString();
}
public static explicit operator ValidatedName(string x)
{
if (IsValid(x))
{
return new ValidatedName(x);
}
throw new InvalidCastException();
}
public static bool operator ==(ValidatedName x, ValidatedName y)
{
return x.Equals(y);
}
public static bool operator !=(ValidatedName x, ValidatedName y)
{
return !x.Equals(y);
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public override string ToString()
{
return _value;
}
}
Das Beispiel zeigt den Token string
, da implicit
dies niemals fehlschlagen kann, aber den string
Cast, explicit
da dies für ungültige Werte wirft, aber natürlich können beide entweder implicit
oder sein explicit
.
Beachten Sie auch, dass man diese Struktur nur über eine Umwandlung von initialisieren kann string
, aber man kann testen, ob eine solche Umwandlung im Voraus mit der IsValid
static
Methode fehlschlägt .
Dies scheint ein gutes Muster zu sein, um die Validierung von Domänenwerten zu erzwingen, die durch einfache Typen dargestellt werden können, aber ich sehe es nicht oft verwendet oder vorgeschlagen, und ich bin interessiert, warum.
Meine Frage lautet also: Was sind für Sie die Vor- und Nachteile der Verwendung dieses Musters und warum?
Wenn Sie der Meinung sind, dass dies ein schlechtes Muster ist, würde ich gerne verstehen, warum und auch was Sie für die beste Alternative halten.
NB Ich habe diese Frage ursprünglich zu Stack Overflow gestellt , sie wurde jedoch als primär meinungsbasiert (ironischerweise subjektiv an sich) zurückgestellt - hoffentlich kann sie hier mehr Erfolg haben.
Oben ist der Originaltext, unten ein paar weitere Gedanken, teilweise als Antwort auf die dort eingegangenen Antworten, bevor er auf Eis gelegt wurde:
- Einer der Hauptpunkte der Antworten war die Menge an Kesselplattencode, die für das obige Muster erforderlich ist, insbesondere wenn viele solcher Typen erforderlich sind. Zur Verteidigung des Musters könnte dies jedoch mithilfe von Vorlagen weitgehend automatisiert werden, und tatsächlich scheint es mir sowieso nicht schlecht zu sein, aber das ist nur meine Meinung.
- Aus konzeptioneller Sicht erscheint es bei der Arbeit mit einer stark typisierten Sprache wie C # nicht seltsam, das stark typisierte Prinzip nur auf zusammengesetzte Werte anzuwenden, anstatt es auf Werte zu erweitern, die durch eine Instanz von a dargestellt werden können eingebauter Typ?