Bagi saya, ini masuk akal karena memberikan nama konkret ke kelas, daripada mengandalkan NamedEntity generik. Di sisi lain, ada sejumlah kelas yang tidak memiliki properti tambahan.
Apakah ada kelemahan dari pendekatan ini?
Pendekatannya tidak buruk, tetapi ada solusi yang lebih baik tersedia. Singkatnya, sebuah antarmuka akan menjadi solusi yang jauh lebih baik untuk ini. Alasan utama mengapa antarmuka dan pewarisan berbeda di sini adalah karena Anda hanya dapat mewarisi dari satu kelas, tetapi Anda dapat mengimplementasikan banyak antarmuka .
Misalnya, pertimbangkan bahwa Anda telah menamai entitas, dan entitas yang diaudit. Anda memiliki beberapa entitas:
One
bukan entitas yang diaudit atau entitas yang dinamai. Itu sederhana:
public class One
{ }
Two
adalah entitas bernama tetapi bukan entitas yang diaudit. Pada dasarnya itulah yang Anda miliki sekarang:
public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Two : NamedEntity
{ }
Three
adalah entri yang dinamai dan diaudit. Di sinilah Anda mengalami masalah. Anda dapat membuat AuditedEntity
kelas dasar, tetapi Anda tidak dapat membuat Three
mewarisi baik AuditedEntity
dan NamedEntity
:
public class AuditedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
{ }
Namun, Anda mungkin memikirkan solusinya dengan AuditedEntity
mewarisi dari NamedEntity
. Ini adalah retasan cerdas untuk memastikan bahwa setiap kelas hanya perlu mewarisi (langsung) dari satu kelas lain.
public class AuditedEntity : NamedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : AuditedEntity
{ }
Ini masih berfungsi. Tetapi apa yang telah Anda lakukan di sini dinyatakan bahwa setiap entitas yang diaudit secara inheren juga merupakan entitas yang dinamai . Yang membawa saya ke contoh terakhir saya. Four
adalah entitas yang diaudit tetapi bukan entitas yang bernama. Tetapi Anda tidak dapat membiarkan Four
warisan dari AuditedEntity
karena Anda juga akan membuatnya menjadi NamedEntity
warisan karena antara AuditedEntity and
NamedEntity`.
Menggunakan warisan, tidak ada cara untuk membuat keduanya Three
dan Four
berfungsi kecuali Anda mulai menduplikasi kelas (yang membuka set masalah yang sama sekali baru).
Menggunakan antarmuka, ini dapat dengan mudah dicapai:
public interface INamedEntity
{
int Id { get; set; }
string Name { get; set; }
}
public interface IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
public class One
{ }
public class Two : INamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Three : INamedEntity, IAuditedEntity
{
public int Id { get; set; }
public string Name { get; set; }
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
public class Four : IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
Satu-satunya kelemahan kecil di sini adalah Anda masih harus mengimplementasikan antarmuka. Tetapi Anda mendapatkan semua manfaat dari memiliki jenis yang dapat digunakan kembali secara umum, tanpa ada kelemahan yang muncul saat Anda memerlukan variasi pada beberapa jenis umum untuk entitas tertentu.
Tapi polimorfisme Anda tetap utuh:
var one = new One();
var two = new Two();
var three = new Three();
var four = new Four();
public void HandleNamedEntity(INamedEntity namedEntity) {}
public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}
HandleNamedEntity(one); //Error - not a named entity
HandleNamedEntity(two);
HandleNamedEntity(three);
HandleNamedEntity(four); //Error - not a named entity
HandleAuditedEntity(one); //Error - not an audited entity
HandleAuditedEntity(two); //Error - not an audited entity
HandleAuditedEntity(three);
HandleAuditedEntity(four);
Di sisi lain, ada sejumlah kelas yang tidak memiliki properti tambahan.
Ini adalah variasi pada pola antarmuka marker , di mana Anda mengimplementasikan antarmuka kosong murni untuk dapat menggunakan jenis antarmuka untuk memeriksa apakah kelas yang diberikan "ditandai" dengan antarmuka ini.
Anda menggunakan kelas bawaan alih-alih antarmuka yang diimplementasikan, tetapi tujuannya sama, jadi saya akan menyebutnya sebagai "kelas bertanda".
Pada nilai nominal, tidak ada yang salah dengan antarmuka / kelas marker. Mereka secara sintaksis dan teknis sah, dan tidak ada kekurangan inheren untuk menggunakannya asalkan penanda secara universal benar (pada waktu kompilasi) dan tidak bersyarat .
Ini adalah persis bagaimana Anda harus membedakan antara pengecualian yang berbeda, bahkan ketika pengecualian itu sebenarnya tidak memiliki sifat / metode tambahan dibandingkan dengan metode dasar.
Jadi pada dasarnya tidak ada yang salah dengan melakukannya, tetapi saya akan menyarankan menggunakan ini dengan hati-hati, memastikan bahwa Anda tidak hanya mencoba untuk menutupi kesalahan arsitektur yang ada dengan polimorfisme yang dirancang dengan buruk.
OrderDateInfo
s dari orang-orang yang relevan dengan lainnyaNamedEntity
s