Zwykle obiekty domeny mają właściwości, które mogą być reprezentowane przez wbudowany typ, ale których prawidłowe wartości stanowią podzbiór wartości, które mogą być reprezentowane przez ten typ.
W takich przypadkach wartość można zapisać za pomocą wbudowanego typu, ale należy upewnić się, że wartości są zawsze sprawdzane w punkcie wejścia, w przeciwnym razie możemy skończyć z nieprawidłową wartością.
Jednym ze sposobów rozwiązania tego problemu jest przechowywanie wartości jako niestandardowej, structktóra ma jedno private readonlypole bazowe typu wbudowanego i której konstruktor sprawdza podaną wartość. Dzięki temu zawsze możemy być pewni, że użyjemy tylko zweryfikowanych wartości struct.
Możemy również zapewnić operatory rzutowania zi do wbudowanego typu bazowego, aby wartości mogły bezproblemowo wchodzić i wychodzić jako typ bazowy.
Weźmy jako przykład sytuację, w której musimy reprezentować nazwę obiektu domeny, a poprawnymi wartościami są dowolne ciągi o długości od 1 do 255 znaków włącznie. Możemy to przedstawić za pomocą następującej struktury:
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;
}
}
Przykład pokazuje To- stringobsada jak implicitjak to nigdy nie może zabraknąć, ale od- stringobsada jak explicitjak to będzie rzucać za nieprawidłowe wartości, ale oczywiście te mogą zarówno być implicitalbo explicit.
Należy również zauważyć, że można zainicjować tę strukturę tylko za pomocą rzutowania z string, ale można przetestować, czy rzutowanie zakończy się niepowodzeniem za pomocą tej IsValid staticmetody.
Wydaje się, że jest to dobry wzorzec wymuszania sprawdzania poprawności wartości domen, które mogą być reprezentowane przez proste typy, ale nie widzę, aby były często używane lub sugerowane i jestem zainteresowany, dlaczego.
Moje pytanie brzmi zatem: jakie są zalety i wady korzystania z tego wzoru i dlaczego?
Jeśli uważasz, że jest to zły wzór, chciałbym zrozumieć, dlaczego i co uważasz za najlepszą alternatywę.
Uwaga : Pierwotnie zadałem to pytanie na temat przepełnienia stosu, ale zostało ono wstrzymane jako oparte głównie na opiniach (ironicznie subiektywne samo w sobie) - mam nadzieję, że może się tutaj cieszyć większym sukcesem.
Powyżej znajduje się oryginalny tekst, poniżej kilka innych przemyśleń, częściowo w odpowiedzi na odpowiedzi otrzymane tam, zanim zostały zawieszone:
- Jednym z głównych argumentów podanych w odpowiedziach była ilość kodu płyty kotła niezbędna do powyższego wzoru, zwłaszcza gdy wymaganych jest wiele takich typów. Jednak w obronie tego wzoru można to w dużej mierze zautomatyzować za pomocą szablonów i właściwie nie wydaje mi się to takie złe, ale to tylko moja opinia.
- Z koncepcyjnego punktu widzenia nie wydaje się dziwne, że podczas pracy z silnie typowanym językiem, takim jak C #, stosowanie silnie typowanej zasady dotyczy tylko wartości złożonych, a nie rozszerzanie jej na wartości, które mogą być reprezentowane przez wystąpienie wbudowany typ?