。NET中的接口实际上已编译成类,纯抽象类,只是在其上具有interface前缀。因此,总的来说,任何接口的实现者都是该接口的继承者,而不是许多书中所写的实现者。是的,我知道接口在企业代码中还有另一个用途-为不相关的类提供通用功能。但是对于MSIL,任何类实际上都是接口的子类型。它给出了仅使用简单的具体类扩展接口的理由,而不是使基本接口的另一个派生接口扩展。因此,当某些客户端引用该接口并且需要向下转换到更具体的实体时,开发人员将创建另一个派生接口并将其向下转换。为什么他们不主动向下转换为具体的派生类,因为它实际上是接口的有效子类型?示例代码:
public inteface IEntity
{
int Id { get; set; }
}
public class Vote : IEntity
{
public int Id { get; set; }
public int SubjectId { get; set; }
public bool Sign { get; set;}
public int UserId {get; set;}
public void Validate()
{
if (UserId == default)
throw new Exception("UserId is not defined");
if (SubjectId == default)
throw new Exception("SubjectId is not defined");
}
}
public abstract class BusinessEngine
{
private readonly IRepository _repo;
public void Save(IEntity entity)
{
BeforeSave(entity);
DoSave(entity); // omit code, it just delegates work to repository
AfterSave();
}
protected virtual void BeforeSave(IEntity entity)
{
}
protected virtual void AfterSave(IEntity entity)
{
}
}
public class VotesBE: BusinessEngine
{
protected override void BeforeSave(IEntity entity)
{
var vote = entity as Vote;
vote.Validate();
}
}
但是许多开发人员更愿意为IEntity
创建另一个派生接口-例如,将扩展基本IValidatableEntity
接口的IEntity
,他们将在BusinessEngine代码中执行此操作:
`public abstract class BusinessEngine
{
private readonly IRepository _repo;
public void Save(IEntity entity)
{
BeforeSave(entity);
DoSave(entity); // omit code, it just delegates work to repository
AfterSave();
}
protected virtual void BeforeSave(IEntity entity)
{
if (entity is IValidatableEntity ve)
ve.Validate();
}
protected virtual void AfterSave(IEntity entity)
{
}
}`
您描述的两种技术都是有效的,但是,您提出的技术可能会使用Generics来实现。
例如:
public abstract class BusinessEngine<TEntity> where TEntity : IEntity
{
private readonly IRepository _repo;
public void Save(TEntity entity)
{
var typedEntity = entity as TEntity;
BeforeSave(entity);
DoSave(entity);
AfterSave();
}
protected virtual void BeforeSave(TEntity entity) { }
protected virtual void AfterSave(TEntity entity) { }
}
public class VoteBusinessEngine : BusinessEngine<Vote>
{
protected override void BeforeSave(Vote entity)
{
vote.Validate();
}
}
现在,您原来的问题是“为什么要以一种方式超越另一种方式?”这取决于您的目标和需求。
如果您的目标是编写可以处理多种类型的实体的通用服务(或服务集合),则可能需要IValidatableEntity
方法。在这种情况下,您可以通过实现其他接口让实体描述其功能。
如果只想为几种实体类型的单个服务添加特殊情况处理,而无需修改实体本身,那么通用方法就很有意义。
这实际上归结为:您想让谁“拥有”特殊行为?实体还是服务?
如果您想更深入,请阅读Role Interfaces和Interface Segregation Principle(SOLID中的'I')。