存储库模式实现

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

interface IProductRepository { IQueryable FindAll(); } 

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

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

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

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

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

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

乔尔说得最好(文字来自维基百科文章 ):

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

Joels博客文章

第二种方法更容易实现,并保持抽象完整。

更新

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

 interface IProductRepository { IEnumerable FindForCategory(int categoryId); IEnumerable FindAllStartingWith(string letter); } interface IPromoCodeRepository { IEnumerable FindForProduct(int productId); } 

换了东西:

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

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

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

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

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

因此,我倾向于使用一个使用IQueryable通用搜索方法和一组多次使用的方法:

 interface IRepository { IQueryable FindAll(); } interface IProductRepository : IRepository { IEnumerable GetProductsInCategory(int categoryId); IEnumerable GetProductsStartingWith(string letter); IEnumerable GetProductPromoCodes(int productId); } 

还要考虑unit testing。 与IQueryable相比,特定方法更容易模拟。

我其实认为第一个更好。 我假设我的决定有以下几个因素:

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

    • IQueryable方法 – 您只需要在代码中更改调用方法。
    • IEnumerables – 您还需要更改方法名称。
  2. 如果有很多人要以多态方式派生您想要迭代的接口:

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

    • IQueryable方法 – 易于分为IEnumerables方法。
    • IEnumerables方法 – 很难转换回IQueryable方法。

因此,我建议您从IQueryable开始作为默认选择,并且随着代码的进展,您可以随时更改为您需要的更具体的IEnumerables方法。