Dependency injection 工厂管理

Dependency injection 工厂管理,dependency-injection,ninject,inversion-of-control,Dependency Injection,Ninject,Inversion Of Control,我使用Ninject.Extensions.Factory来控制存储库层的生命周期。我希望有一个单一的参考点,从中我可以获得对所有存储库的参考,并使它们可以懒洋洋地使用。Ninject工厂方法似乎是一个很好的解决方案,但我不太确定我的解决方案: public class PublicUow : IPublicUow { private readonly IPublicRepositoriesFactory _publicRepositoriesFactory; public P

我使用Ninject.Extensions.Factory来控制存储库层的生命周期。我希望有一个单一的参考点,从中我可以获得对所有存储库的参考,并使它们可以懒洋洋地使用。Ninject工厂方法似乎是一个很好的解决方案,但我不太确定我的解决方案:

public class PublicUow : IPublicUow
{
    private readonly IPublicRepositoriesFactory _publicRepositoriesFactory;

    public PublicUow(IPublicRepositoriesFactory publicRepositoriesFactory)
    {
        _publicRepositoriesFactory = publicRepositoriesFactory;
    }

    public IContentRepository ContentRepository { get { return _publicRepositoriesFactory.ContentRepository; } }
    public ICategoryRepository CategoryRepository { get { return publicRepositoriesFactory.CategoryRepository; } }
}
问题在于PublicRepositories类

public class PublicRepositoriesFactory : IPublicRepositoriesFactory
{
    private readonly IContentRepositoryFactory _contentRepositoryFactory;
    private readonly ICategoryRepositoryFactory _categoryRepositoryFactory;

    public PublicRepositoriesFactory(IContentRepositoryFactory contentRepositoryFactory, ICategoryRepositoryFactory categoryRepositoryFactory)
    {
        _contentRepositoryFactory = contentRepositoryFactory;
        _categoryRepositoryFactory = categoryRepositoryFactory;
    }

    public IContentRepository ContentRepository { get { return _contentRepositoryFactory.CreateContentRepository(); } }
    public ICategoryRepository CategoryRepository { get { return _categoryRepositoryFactory.CreateCategoryRepository(); } }
}
我担心随着存储库数量的增加,这将变得难以管理,这个类在当前实现中可能需要大约20-30个构造函数参数。 有没有一种方法可以减少ctr参数的数量,比如传递接口数组/字典或类似的东西

我曾经考虑过在这个场景中使用属性注入,但大多数文章建议一般避免使用属性注入

是否有一种更通用的模式可以让这更容易管理


这通常是一种好方法吗?

使用存储库接口(如

public interface IRepository
{
    T LoadById<T>(Guid id);

    void Save<T>(T entity);

    ....
}
因此,基本上您所做的唯一更改就是将
GetParentCategoriesQuery
提取到它自己的类中。DbContext实例必须与其他查询和存储库实例共享。对于web项目,这是通过绑定
DbContext
.InRequestScope()
完成的。对于其他应用,您可能需要使用另一种机制

查询的用法非常简单:

public class CategoryController
{
   private readonly IRepository repository;
   private readonly IGetParentCategoriesQuery getParentCategoriesQuery;

   public CategoryController(
            IRepository repository, 
            IGetParentCategoriesQuery getParentCategoriesQuery)
   {
       this.repository = repository;
       this.getParentCategoriesQuery = getParentCategoriesQuery;
   }

   public void Process(Guid categoryId)
   {
       Category category = this.repository.LoadById(categoryId);
       IEnumerable<Category> parentCategories = 
           this.getParentCategoriesQuery(category);

       // so some stuff...
   }
}
其使用方式如下:

IEnumerable<Category> parents = repository
    .CreateQuery<GetParentCategoriesQuery>()
    .GetParents(someCategory);
IEnumerable parents=存储库
.CreateQuery()
.GetParents(someCategory);
但是请注意,这种替代方法只会延迟创建查询,从而导致可测试性降低(绑定问题可能在更长时间内未被检测到)


GetParentCategoriesQuery
是存储库层的一部分,但不是存储库类的一部分。

在我的例子中,每个存储库都是IRepository的超集,它扩展了一个基类,因此提供了所有通用功能。上面提到过,我还没有遇到一个真实世界的应用程序,在这个应用程序中,每个域实体都没有特定的逻辑。例如,GetParentCategories和GetRecentContents是两个完全不同的实现,不能与简单的IRepository一起使用。另外,如果我错了,请纠正我的错误(在这方面还是新手),但在我当前的实现中,没有服务定位器反模式,因为我从未在组合根之外引用IOC容器?像
GetParentCategories
GetRecentContents
这样的方法不属于存储库(SOC、SRP),intead每个类都应该放在一个单独的类中,比如
GetParentCategoriesQuery
。这样做之后,您将看到每个存储库类现在只继承基类,而不再做其他任何事情……至于服务定位器反模式:在Mark Seeman引用的文章中,他描述了为什么不延迟/延迟实例化类型是有益的。争论更多的是关于可测试性和对象树更易于理解/维护,而不是关于服务位置。顺便说一句,自动生成的工厂本身引用了容器,并且正在使用服务位置?在需要父类别的地方,我需要实例化一个新对象,并通过构造函数注入提供依赖关系?您是否可以修改您的答案并添加一些代码,以澄清所述类与存储库层的交互,并显示一个简单的用例?好的,我已经这样做了。在SO中也有其他帖子介绍了这一点,但我很惊讶google搜索结果中出现了很多设计糟糕的例子,其中一些是微软自己的。
public TQuery CreateQuery<TQuery>()
{
    return this.queryFactory.Create<TQuery>(this.context);
}
IEnumerable<Category> parents = repository
    .CreateQuery<GetParentCategoriesQuery>()
    .GetParents(someCategory);