作为用于继承的接口,而不是实现者使用的接口

问题描述 投票:1回答:1

。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) 
      {
      }
}`
c# asp.net .net .net-core
1个回答
0
投票

您描述的两种技术都是有效的,但是,您提出的技术可能会使用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 InterfacesInterface Segregation PrincipleSOLID中的'I')。

© www.soinside.com 2019 - 2024. All rights reserved.