Saya tidak menganggap diri saya seorang ahli DDD tetapi, sebagai arsitek solusi, cobalah untuk menerapkan praktik terbaik bila memungkinkan. Saya tahu ada banyak diskusi di sekitar pro dan kontra tentang "gaya" setter no (publik) di DDD dan saya bisa melihat kedua sisi argumen. Masalah saya adalah bahwa saya bekerja pada tim dengan beragam keterampilan, pengetahuan, dan pengalaman yang artinya saya tidak bisa percaya bahwa setiap pengembang akan melakukan hal-hal dengan cara yang "benar". Misalnya, jika objek domain kami dirancang sedemikian rupa sehingga perubahan pada keadaan internal objek dilakukan oleh suatu metode tetapi memberikan setter properti publik, seseorang akan tak terhindarkan mengatur properti alih-alih memanggil metode tersebut. Gunakan contoh ini:
public class MyClass
{
public Boolean IsPublished
{
get { return PublishDate != null; }
}
public DateTime? PublishDate { get; set; }
public void Publish()
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
PublishDate = DateTime.Today;
Raise(new PublishedEvent());
}
}
Solusi saya adalah membuat setter properti menjadi privat yang dimungkinkan karena ORM yang kami gunakan untuk menghidrasi objek menggunakan refleksi sehingga dapat mengakses seter pribadi. Namun, ini menimbulkan masalah ketika mencoba menulis unit test. Misalnya, ketika saya ingin menulis unit test yang memverifikasi persyaratan yang tidak dapat kami terbitkan kembali, saya perlu menunjukkan bahwa objek tersebut telah diterbitkan. Saya pasti dapat melakukan ini dengan memanggil Terbitkan dua kali, tetapi kemudian pengujian saya mengasumsikan bahwa Publikasi diimplementasikan dengan benar untuk panggilan pertama. Sepertinya agak bau.
Mari buat skenario sedikit lebih nyata dengan kode berikut:
public class Document
{
public Document(String title)
{
if (String.IsNullOrWhiteSpace(title))
throw new ArgumentException("title");
Title = title;
}
public String ApprovedBy { get; private set; }
public DateTime? ApprovedOn { get; private set; }
public Boolean IsApproved { get; private set; }
public Boolean IsPublished { get; private set; }
public String PublishedBy { get; private set; }
public DateTime? PublishedOn { get; private set; }
public String Title { get; private set; }
public void Approve(String by)
{
if (IsApproved)
throw new InvalidOperationException("Already approved.");
ApprovedBy = by;
ApprovedOn = DateTime.Today;
IsApproved = true;
Raise(new ApprovedEvent(Title));
}
public void Publish(String by)
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
if (!IsApproved)
throw new InvalidOperationException("Cannot publish until approved.");
PublishedBy = by;
PublishedOn = DateTime.Today;
IsPublished = true;
Raise(new PublishedEvent(Title));
}
}
Saya ingin menulis unit test yang memverifikasi:
- Saya tidak dapat menerbitkan kecuali Dokumen telah disetujui
- Saya tidak dapat menerbitkan kembali Dokumen
- Saat dipublikasikan, nilai-nilai PublishedBy dan PublishedOn diatur dengan benar
- Saat dipublikasikan, Publikasi muncul
Tanpa akses ke setter, saya tidak bisa memasukkan objek ke dalam kondisi yang diperlukan untuk melakukan tes. Membuka akses ke setter mengalahkan tujuan mencegah akses.
Bagaimana Anda menyelesaikan (d) masalah ini?