分割CRUD存储库时DI的问题

时间:2018-01-17 13:56:18

标签: c# dependency-injection repository-pattern

我已经想到将我的ICrudRepository分解为4个单独的存储库:ICreatableRepositoryIReadableRepository等,每个操作类型一个。每个都有自己的实现,将进行操作。我想这样做是因为我可能有一个我只想拥有读访问权限的存储库,在这种情况下我只会实现IReadableRepository<T, TId>,而不是实现ICrudRepository一堆未实现的方法

public interface ICreatableRepository<T>
{
    Task Create(T model);
}

到目前为止一直很好,但请考虑以下因素:

public interface IMyNewCrudRepository<T, TId> : 
    ICreatableRepository<T>,
    IReadableRepository<T, TId>,
    IUpdatableRepository<T>,
    IDeletableRepository<TId>
{}

public abstract class BaseCrudRepository<TModel, TId> : IMyNewCrudRepository<TModel, TId>
{
    private readonly ICreatableRepository<TModel> _creatableRepository;
    private readonly IReadableRepository<TModel, TId> _readableRepository;
    private readonly IUpdatableRepository<TModel> _updatableRepository;
    private readonly IDeletableRepository<TId> _deletableRepository;

    protected BaseCrudRepository(ICreatableRepository<TModel> creatableRepository, IReadableRepository<TModel, TId> readableRepository, IUpdatableRepository<TModel> updatableRepository, IDeletableRepository<TId> deletableRepository)
    {
        _creatableRepository = creatableRepository;
        _readableRepository = readableRepository;
        _updatableRepository = updatableRepository;
        _deletableRepository = deletableRepository;
    }

    public async Task Create(TModel model)
    {
        await _creatableRepository.Create(model);
    }

    //other implemented methods
}

这将是一个快捷方式,当我执行想要每个CRUD操作时,我不必实现所有4个接口并使存储库混乱。

我认为这很棒,直到我想到如何注射它。由于BaseCrudRepository依赖于DI的所有4个单独的crud实现,我现在必须根据模型对这些进行DI吗?

我想一个选择是在base的构造函数中创建它们而不是注入它们,但这会是反模式吗?

1 个答案:

答案 0 :(得分:0)

如果您的具体存储库类实现了此接口:

public interface IMyNewCrudRepository<T, TId> : 
    ICreatableRepository<T>,
    IReadableRepository<T, TId>,
    IUpdatableRepository<T>,
    IDeletableRepository<TId>
{}

那么你已经完成了我认为你正在寻找的抽象和界面隔离。将存储库分成不同的类可能是不必要的。将存储库分成多个类,每个类实现不同的接口,然后将它们重新组合成一个实现所有接口的类几乎肯定是不必要的。为什么把他们拆开只是为了让他们重新组合起来?

public class NeedsToReadFromRepository<Thing>
{
    private readonly IReadableRepository<Thing, Guid> _repository;

    public NeedsToReadFromRepository(IReadableRepository<Thing, Guid> repository)
    {
        _repository = repository;
    }
}

消费者只依赖于接口,因此如果一个类实现所有接口并不重要。有时可能有理由拆分一个类(单一责任原则),但您不需要拆分该类以获得接口隔离原则的好处。

而且,正如评论中所提到的,如果需要将其拆分,那么为每个操作设置一个单独的界面可能会有点过分。

如果你更精确地拆分它,那么你需要注册更多的DI。我绝不建议使用比您需要更少的接口来避免额外的DI注册。但在进行极端细化之前,可能需要考虑一些事项。