通用存储库,DI,聚合根

时间:2012-01-04 12:11:21

标签: c# design-patterns dependency-injection repository ninject

拥有像

这样的通用存储库
public class Repository<T> 
    where T: Entity<T> 
{ 
    /*anything else*/ 
}

应该是每个聚合根的具体存储库,如

class ProductRepository : Repository<Product> 
{
} 

class CategoryRepository : Repository<Category> 
{ 
}

被创造?

另外,我如何使用DI(Ninject)与存储库的通用实现。

样品是apreciated!

谢谢!

1 个答案:

答案 0 :(得分:5)

我在SO中的问题中看到了很多滥用泛型的问题,虽然它并不一定会引用你的问题(虽然这有助于澄清),但我认为一旦在这里写了一个摘要。

泛型是typeless重用行为(几乎,因为你可以使用限制来限制类型)。如果所有类型(或限制为限制的行为)共享行为,则使用泛型。

但是,如果每个泛型类型的实现需要单独实现,那么使用泛型并没有帮助,而是简化为装饰 - 对我来说这是糟糕的设计。

好的,我们举个例子:

interface IConverter<T1, T2>
{
    T1 Convert(T2 t2);
}

这看起来像一个很好的泛型(将一种类型转换为另一种类型),但我必须将所有类型的类型组合实现为不同的转换器。而IConverter<Apple, Orange>没有任何意义。因此,这里的仿制药具有误导性和不好意思。

现在回到存储库。关于这个特定问题有很多文章(很多争议),但这是个人我的看法:

通常不建议使用通用存储库。 但是,根据我的个人经验,我使用通用存储库来实现常见的东西(由基础仓库实现),如果还有其他的话,则使用个别的:

interface IRepository<T>
{
    T GetById(int id);
    IEnumerable<T> GetAll();
    void Save(T t);
}

class BaseRepository<T> : IRepository<T>
{
   ... // implement common methods
}

interface IProductRepository : IRepository<T>
{
    IEnumerable<T> GetTop5BestSellingProducts();    
}

class ProductRepository : BaseRepository<T>, IProductRepository 
{
    ... // implement important methods
}

注意

有些人认为存储库必须允许将标准传递到存储库(Eric Evans DDD book),但我再次认为我不必同意这一点。我更喜欢存储库中的域名重要声明(例如GetTopFiveBestSellingProductsGetTopBestSellingProducts),除非报告编写者中有100个这样的声明只占案例的1%。


第二个问题:

我不使用Ninject但是对于任何DI,这是你如何做的

 // PSEUDOCODE !!!
 container.Register<IProductRepository , ProductRepository>(); 

取决于DI框架,它可能会略有不同。