Umumnya objek domain memiliki properti yang dapat diwakili oleh tipe bawaan tetapi nilai validnya adalah subset dari nilai yang mungkin diwakili oleh tipe itu.
Dalam kasus ini, nilai dapat disimpan menggunakan tipe bawaan tetapi perlu untuk memastikan bahwa nilai selalu divalidasi pada titik masuk, jika tidak kita akhirnya akan bekerja dengan nilai yang tidak valid.
Salah satu cara untuk mengatasi ini adalah dengan menyimpan nilai sebagai kebiasaan struct
yang memiliki private readonly
bidang dukungan tunggal dari tipe bawaan dan yang konstruktornya memvalidasi nilai yang diberikan. Kami kemudian dapat selalu yakin hanya menggunakan nilai yang divalidasi dengan menggunakan struct
tipe ini .
Kami juga dapat menyediakan operator cor dari dan ke tipe bawaan yang mendasarinya sehingga nilai-nilai dapat masuk dan keluar dengan mulus sebagai jenis yang mendasarinya.
Ambil contoh situasi di mana kita perlu mewakili nama objek domain, dan nilai yang valid adalah string apa pun yang panjangnya antara 1 dan 255 karakter. Kami dapat mewakili ini menggunakan struct berikut:
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;
}
}
Contoh ini memperlihatkan string
pemain karena implicit
hal ini tidak akan pernah gagal tetapi dari string
pemain explicit
karena hal ini akan menghasilkan nilai yang tidak valid, tetapi tentu saja ini bisa berupa implicit
atau explicit
.
Perhatikan juga bahwa seseorang hanya dapat menginisialisasi struct ini dengan cara pemain dari string
, tetapi orang dapat menguji apakah pemain tersebut akan gagal di muka menggunakan IsValid
static
metode ini.
Ini tampaknya menjadi pola yang baik untuk menegakkan validasi nilai domain yang dapat diwakili oleh tipe sederhana, tetapi saya tidak melihatnya sering atau disarankan dan saya tertarik mengapa.
Jadi pertanyaan saya adalah: apa yang Anda lihat sebagai keuntungan dan kerugian dari menggunakan pola ini, dan mengapa?
Jika Anda merasa ini adalah pola yang buruk, saya ingin memahami mengapa dan apa yang Anda rasakan adalah alternatif terbaik.
NB Saya awalnya mengajukan pertanyaan ini pada Stack Overflow tapi itu ditunda terutama berdasarkan opini (ironisnya subjektif sendiri) - mudah-mudahan bisa menikmati lebih banyak kesuksesan di sini.
Di atas adalah teks asli, di bawah beberapa pemikiran lagi, sebagian sebagai jawaban atas jawaban yang diterima di sana sebelum ditunda:
- Salah satu poin utama yang dibuat oleh jawaban adalah sekitar jumlah kode pelat ketel yang diperlukan untuk pola di atas, terutama ketika banyak jenis seperti itu diperlukan. Namun dalam mempertahankan pola, ini sebagian besar bisa secara otomatis menggunakan template dan sebenarnya bagi saya sepertinya tidak terlalu buruk, tapi itu hanya pendapat saya.
- Dari sudut pandang konseptual, apakah tidak aneh ketika bekerja dengan bahasa yang sangat diketik seperti C # untuk hanya menerapkan prinsip yang sangat diketik untuk nilai komposit, daripada memperluasnya ke nilai-nilai yang dapat diwakili oleh turunan dari tipe bawaan?