对我来说,这很有意义,因为它为类提供了具体的名称,而不是依赖于通用的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之间的继承and
NamedEntity`。
使用继承,除非您开始复制类(否则会带来一系列新的问题),否则无法同时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);
另一方面,有许多这样的类根本没有其他属性。
这是标记接口模式的一种变体,您在其中实现了一个空接口,纯粹是为了能够使用接口类型来检查给定的类是否已被该接口“标记”。
您使用继承的类而不是实现的接口,但是目标是相同的,因此我将其称为“标记类”。
从表面上看,标记接口/类没有错。它们在语法上和技术上都是有效的,并且只要标记是普遍正确的(在编译时)并且不是有条件的,使用它们就不会存在固有的缺点。
这就是您应该如何区分不同的异常,即使与基础方法相比,这些异常实际上没有任何其他属性/方法。
因此,这样做本质上并没有错,但是我建议您谨慎使用,以确保您不只是试图通过设计不良的多态性掩盖现有的体系结构错误。
OrderDateInfo
s 相关的方法与与其他NamedEntity
s 相关的方法