Для мене це має сенс, оскільки воно дає конкретну назву класу, а не покладатися на загальну NamedEntity. З іншого боку, існує ряд таких класів, які просто не мають додаткових властивостей.
Чи є якісь недоліки у цього підходу?
Підхід непоганий, але є кращі рішення. Коротше кажучи, інтерфейс був би набагато кращим рішенням для цього. Основна причина, чому інтерфейси та успадкування тут різні, полягає в тому, що ви можете успадковувати лише один клас, але ви можете реалізувати багато інтерфейсів .
Наприклад, врахуйте, що ви назвали суб’єкти та суб'єкти, що перевіряються. У вас є кілька об'єктів:
Oneне є суб'єктом аудиту, ані іменованним суб'єктом. Все просто:
public class One
{ }
Twoє названим суб'єктом господарювання, але не є аудитором. Це по суті те, що у вас зараз:
public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Two : NamedEntity
{ }
Threeє іменованим, і ревізованим записом. Тут ви стикаєтеся з проблемою. Ви можете створити AuditedEntityбазовий клас, але ви не можете зробити Threeспадкове і те, AuditedEntity і NamedEntity :
public class AuditedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
{ }
Однак ви можете подумати про вирішення проблеми, отримавши AuditedEntityспадок від NamedEntity. Це розумний хак для того, щоб забезпечити, що кожен клас повинен успадковувати (безпосередньо) один клас.
public class AuditedEntity : NamedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : AuditedEntity
{ }
Це все ще працює. Але те, що ви тут зробили, - це те, що кожен суб'єкт, що перевіряється, по суті є також названою сутністю . Що підводить мене до мого останнього прикладу. Fourє аудиторською організацією, але не іменованою організацією. Але ви не можете дозволити спадщині Fourз того, AuditedEntityяк ви тоді також зробили б це NamedEntityзавдяки спадщині між AuditedEntity andNamedEntity ".
Використовуючи спадщину, немає способу зробити так Threeі Fourпрацювати, якщо ви не почнете дублювати класи (що відкриває цілий новий набір проблем).
Використовуючи інтерфейси, цього легко досягти:
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; }
}
Єдиним незначним недоліком тут є те, що вам все одно доведеться реалізувати інтерфейс. Але ви отримуєте всі переваги від загального багаторазового використання без будь-яких недоліків, які виникають, коли вам потрібні варіанти для декількох загальних типів для даної сутності.
Але ваш поліморфізм залишається недоторканим:
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);
З іншого боку, існує ряд таких класів, які просто не мають додаткових властивостей.
Це зміна схеми інтерфейсу маркера , де ви реалізуєте порожній інтерфейс виключно, щоб мати можливість використовувати тип інтерфейсу, щоб перевірити, чи заданий клас "позначений" цим інтерфейсом.
Ви використовуєте успадковані класи замість реалізованих інтерфейсів, але мета та сама, тому я буду називати це "позначеним класом".
З номіналом немає нічого поганого в маркерних інтерфейсах / класах. Вони синтаксично і технічно справедливі, і немає властивих недоліків їх використання за умови, що маркер є універсальним істинним (під час компіляції) і не є умовним .
Саме так слід розмежовувати різні винятки, навіть коли ці винятки насправді не мають додаткових властивостей / методів порівняно з базовим методом.
Так що в цьому немає нічого поганого, але я б радив використовувати це обережно, переконуючись, що ви не просто намагаєтесь приховати існуючу архітектурну помилку погано розробленим поліморфізмом.
OrderDateInfos, від тих, які стосуються іншихNamedEntitys