存储库模式实现

时间:2012-04-17 11:30:50

标签: c# design-patterns

似乎每个我找到的存储库模式的例子,实现在某种程度上都是不同的。以下是我主要找到的两个例子。

interface IProductRepository
{
    IQueryable<Product> FindAll();
}

然后通常有另一个层与存储库通信并调用FindAll()方法并执行任何操作,例如查找以字母“s”开头的产品或获取特定类别的产品。

另一个例子我发现很多将所有的find方法放入存储库

interface IProductRepository
{
    IEnumerable<Product> GetProductsInCategory(int categoryId);
    IEnumerable<Product> GetProductsStartingWith(string letter);
    IEnumerable<PromoCode> GetProductPromoCodes(int productId);
}

您建议我选择哪条路径?或者彼此的优点/缺点是什么?

根据我的理解,阅读http://martinfowler.com/eaaCatalog/repository.html第一种方法似乎最能反映这一点?

5 个答案:

答案 0 :(得分:16)

第一个是可怕的。 IQueryable就像GOD object。很难找到100%完整的实现(即使在所有OR / Ms中)。您可以直接公开ORM而不是使用它,因为否则您可能会获得leaky abstraction layer

乔尔说得最好(文字来自wikipedia article):

  

在Spolsky的文章中,他提到了很多关于抽象的例子,这些抽象在大多数时候都有效,但是底层复杂性的细节不容忽视,从而将复杂性推向应该通过抽象简化的软件本身

Joels blog entry

第二种方法更容易实现并保持抽象不变。

<强>更新

您的存储库违反了单一责任原则,因为它有两个原因需要更改。第一个是如果更改Products API,另一个是更改PromoCode API。你应该使用两个不同的存储库,如:

interface IProductRepository
{
    IEnumerable<Product> FindForCategory(int categoryId);
    IEnumerable<Product> FindAllStartingWith(string letter);
}

interface IPromoCodeRepository
{
    IEnumerable<PromoCode> FindForProduct(int productId);
}

改变了一切:

  • 我倾向于在返回多个项目时使用Find开始方法,如果返回单个项目,则会Get
  • 较短的方法名称=更易于阅读。
  • 单一责任。更容易分辨使用存储库的类对依赖项的影响。

小的定义好的接口可以更容易地发现违反SOLID原则的行为,因为类的中断原则往往会使得构造函数变得臃肿。

答案 1 :(得分:1)

共识正在建立:第二种选择。除了查询逻辑泄漏到IQueryable的所有地方,正确实现它的困难,TEST和mock非常困难。

答案 2 :(得分:0)

我个人建议使用第二个例子,这样你就可以将搜索逻辑封装在一个地方,并且调用者的意图由他们调用的方法的名称明确定义。如果您使用第一个示例,您的查询代码将在整个应用程序中泄漏,您将最终重复查询。

答案 3 :(得分:0)

我建议避免重复。这是第一个目标。如果你有逻辑可以在几个地方找到以某个字母开头的产品,那么它就是一个特例,它的价值被提取到单独的方法中(它也为你的特定情况提供了很好的描述)。没有重复的代码更容易更改,理解和维护。

所以,我倾向于使用一个带有IQueryable的通用搜索方法和一组多次使用的方法:

interface IRepository<T>
{
    IQueryable<T> FindAll();
}

interface IProductRepository : IRepository<Product>
{
    IEnumerable<Product> GetProductsInCategory(int categoryId);
    IEnumerable<Product> GetProductsStartingWith(string letter);
    IEnumerable<PromoCode> GetProductPromoCodes(int productId);
}

还要考虑单元测试。与IQueryable相比,特定方法更易于模拟。

答案 4 :(得分:0)

我实际上认为第一个更好。我假设我决定以下因素:

  1. 如果产品结构将被重构:

    • IQueryable方法 - 您只需要在代码中更改调用方法。
    • IEnumerables - 您还需要更改方法名称。

  2. 如果有很多人想要以多态方式派生你想要迭代的接口:

    • IQueryable方法 - 通用统一方法名称的好处
    • IEnumerables - 某些名称可能没有描述您需要的方法。

  3. Elasticness

    • IQueryable方法 - 易于划分为IEnumerables方法。
    • IEnumerables方法 - 难以转换回IQueryable方法。
  4. 因此,我建议您从IQueryable开始作为默认选择,并且随着代码的进展,您可以随时更改为您需要的更具体的IEnumerables方法。