【问题标题】:Interface Segregation with Repository Pattern Good or Bad?存储库模式的接口隔离是好是坏?
【发布时间】:2014-02-04 20:10:36
【问题描述】:

我想使用存储库模式并创建一个通用的可重用组件。我注意到,当我使用以下接口和基类时,我发现有时我没有实现某些方法(例如,有时我从不需要调用 getAll() 来检索所有对象的列表,不需要该操作在我的特定课程申请中)。

public interface IRepository<TEntity, TId>
{
   void Delete(TEntity entity);
   TEntity Get(TId id);
   IEnumerable<TEntity> GetAll();
   void Save();
   void Update(TEntity entity);
   void Create(TEntity entity);
}

我决定将胖接口分成更小的迷你接口。然后,我想出了一些可以组合在一起的小实现,以获得您的存储库实现所需的确切内容。以下是我想出的。任何人都可以就以下解决方案存在的问题给我建议吗?

public abstract class Entity<TId> : IEntityIdentity<TId>
{
    public TId Id { get; set; }
}

public interface IEntityIdentity<TId>
{
    TId Id { get; set; }
}


public interface IDeleteRepository<TEntity, TId> where TEntity : Entity<TId>
{
    void Delete(TEntity entity);
}

public class DeleteRepository<TEntity, TId> : IDeleteRepository<TEntity, TId> where TEntity : Entity<TId>
{
    private readonly DbContext _dbContext;

    public DeleteRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }


    public void Delete(TEntity entity)
    {
        _dbContext.Set<TEntity>().Remove(entity);
    }
}

public interface ISaveRepository<TEntity, TId> where TEntity : Entity<TId>
{
    void Save(TEntity entity);
}

public class SaveRepository<TEntity, TId> : ISaveRepository<TEntity, TId> where TEntity : Entity<TId>
{

     private readonly DbContext _dbContext;

     public SaveRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }


    public void Save(TEntity entity)
    {
        _dbContext.SaveChanges();
    }
}

public interface IUpdateRepository<TEntity, TId> where TEntity : Entity<TId>
{
    void Update(TEntity entity);
}

public class UpdateRepository<TEntity, TId> : IUpdateRepository<TEntity, TId> where TEntity : Entity<TId>
{

    private readonly DbContext _dbContext;

    public UpdateRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void Update(TEntity entity)
    {
        _dbContext.Entry(entity).State = EntityState.Modified;
    }
}

public interface IGetRepository<TEntity, TId> where TEntity : Entity<TId>
{
    TEntity Get(TId id);
}

public class GetRepository<TEntity, TId> : IGetRepository<TEntity, TId> where TEntity : Entity<TId>
{
    private readonly DbContext _dbContext;

    public GetRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public TEntity Get(TId id)
    {
        return _dbContext.Set<TEntity>().Find(id);
    }
}

public interface IGetAllRepository<TEntity, TId> where TEntity : Entity<TId>
{
    IEnumerable<TEntity> GetAll();
}

public class GetAllRepository<TEntity, TId> : IGetAllRepository<TEntity, TId> where TEntity : Entity<TId>
{
    private readonly DbContext _dbContext;

    public GetAllRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IEnumerable<TEntity> GetAll()
    {
        return _dbContext.Set<TEntity>();
    }
}

public interface ICreateRepository<TEntity, TId> where TEntity : Entity<TId>
{
    void Create(TEntity entity);
}

public class CreateRepository<TEntity, TId> : ICreateRepository<TEntity, TId> where TEntity : Entity<TId>
{
    private readonly DbContext _dbContext;

    public CreateRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void Create(TEntity entity)
    {
        _dbContext.Set<TEntity>().Add(entity);
    }
}

public class RepositoryCombiner<TEntity, TId> : IGetRepository<TEntity, TId>, IGetAllRepository<TEntity, TId> where TEntity : Entity<TId>
{
    private readonly IGetRepository<TEntity, TId> _getRepository;
    private readonly IGetAllRepository<TEntity, TId> _getAllRepository;

    public RepositoryCombiner(IGetRepository<TEntity, TId> getRepository, IGetAllRepository<TEntity, TId> getAllRepository)
    {
        _getRepository = getRepository;
        _getAllRepository = getAllRepository;
    }

    public TEntity Get(TId id)
    {
       return  _getRepository.Get(id);
    }

    public IEnumerable<TEntity> GetAll()
    {
        return _getAllRepository.GetAll();
    }
}

【问题讨论】:

  • 我将两者混合使用。我有单独的角色(接口)并在一个存储库上实现所需的功能,而不是每个角色都有一个存储库。
  • 让我想起了 Udi Dahan 的明确角色:infoq.com/presentations/Making-Roles-Explicit-Udi-Dahan 为什么不呢,但是用 C# IMO 这样的语言来表达有点冗长和笨拙

标签: design-patterns domain-driven-design repository-pattern ddd-repositories


【解决方案1】:

在我看来,您似乎想多了。如果其他人查看您的代码,可能不太清楚您要完成什么。我建议您追求可维护性而不是过早的优化,这是您的目标。

如果最终,某些方法从未在您的代码库中使用,并且您的项目已完成代码,那么删除未调用的方法可能是有意义的。但就目前而言,我将只使用标准存储库模式,并将您的时间和精力集中在应用程序的其他领域。

其他人是否会这样做取决于他们,但对于检索数据,我只使用一个 GetQueryable(),然后根据需要执行 .Single()、.First 或 .All() - 加上如果您的底层存储相当好地支持 IQueryable,您的查询可以变得更加优化。

【讨论】:

    【解决方案2】:

    在真正需要的时候使用接口隔离原则并不是一个坏主意。但在您的情况下,我建议您将layer super type pattern 与存储库模式一起使用。一般来说,尽量让事情变得简单,易于阅读、理解、扩展和维护。我见过大多数人在数据访问和存储层特别犯错误。数据访问层中的代码重复可能具有成本效益,但在未来的变化中会很麻烦。

    【讨论】:

      猜你喜欢
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多