17

似乎我发现的存储库模式的每个示例,在某些方面的实现都是不同的。以下是我主要找的两个例子。

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

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

我发现很多其他示例将所有查找方法放入存储库

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

你建议我走哪条路?或者彼此有什么优点/缺点?

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

4

5 回答 5

16

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

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

在 Spolsky 的文章中,他提请注意许多在大多数情况下都有效的抽象示例,但其中的底层复杂性的细节不容忽视,从而将复杂性推向了本应由抽象本身简化的软件

乔尔斯博客条目

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

更新

您的存储库违反了单一职责原则,因为它有两个更改理由。第一个是 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 原则的行为,因为违反原则的类往往会导致构造函数臃肿。

于 2012-04-17T11:34:53.943 回答
1

共识正在建立:一直是第二个选项。除了 IQueryable 的查询逻辑到处泄漏,很难正确实现之外,很难测试和模拟。

于 2012-04-17T12:00:09.547 回答
0

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

于 2012-04-17T11:35:11.390 回答
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 更容易模拟。

于 2012-04-17T11:37:13.327 回答
0

其实我觉得第一个更好。我假设我的决定基于以下因素:

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

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

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

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

  3. 弹性

    • IQueryable 方法 - 容易分为 IEnumerables 方法。
    • IEnumerables 方法 - 很难转换回 IQueryable 方法。

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

于 2012-04-17T12:00:01.460 回答