规格模式,Func <T,bool>谓词和管道和过滤器的比较

RPM*_*984 7 architecture extension-methods design-patterns specification-pattern pipes-filters

我正在做一些研发工作,因此正在研究设计模式.我最近一直在阅读规范模式,并参考了这篇伟大的文章.

我对代码的简洁性和清洁度很感兴趣,但我开始比较使用其他技术实现相同的清洁度.

考虑以下服务层的接口合同:

public interface IFooDataService
{
   ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification);
   ICollection<Foo> GetFooByPredicate(Func<Foo,bool> predicate);
   ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs);
}
Run Code Online (Sandbox Code Playgroud)

所以,一些初步要点:

  • 这三个都返回了Foo对象的集合
  • 这三个人只有一个论点
  • 规范方法限制对特定要求的访问
  • 谓词方法基本没有限制
  • 搜索args方法限制对特定要求的访问

现在,进入实施:

public ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification)
{
    return fooDataRepository
            .Find()
            .Where(f => specification.IsSatisfiedBy(f))
            .ToList();
}

public ICollection<Foo> GetFooByPredicate(Func<Foo, bool> predicate)
{
    return fooDataRepository
            .Find()
            .Where(predicate)
            .ToList();
}

public ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs)
{
    return fooDataRepository
            .Find()
            .WhereMeetsSearchCriteria(searchArgs)
            .ToList();
}
Run Code Online (Sandbox Code Playgroud)

实施要点:

  • 这三个都非常简单的实现(一行链式代码)
  • 规范和搜索Args过滤在外部实施.
  • 搜索args方法只是使用IEnumerable扩展方法来检查args

那么,话虽如此,在什么条件下你会使用上述3种技术之一?

我对规范模式的看法:

  • 很好,它将业务/域要求隔离成可重用的组件
  • 非常容易阅读,使代码说英语
  • 涉及一些代码(接口,抽象类).如果我要使用它,我会将抽象放在一个通用的程序集中(所以我的解决方案中没有一堆静态文件).
  • 仅通过更改规范而非服务层来轻松更改要求.
  • 域逻辑的最高可测试性(规范)

我对扩展方法(管道和过滤器)的看法:

  • 逻辑上"重量级",但仍然导致相同的简单性.
  • 将查询逻辑从服务层隔离到静态方法
  • 仍然需要排序的"反射"(检查提供的搜索参数和构建查询)
  • 允许您首先编写体系结构(存储库,服务层),而不考虑特定的业务需求(在某些情况下很方便)

我对谓词方法的看法:

  • 可以在需要对查询进行粗粒度控制的地方使用.
  • 适用于规格可能过度的小型项目

我最后的思考逻辑是,如果您正在开发一个复杂的业务应用程序,其中业务需求是预先知道的,但可能会随着时间而改变,那么我将使用规范模式.

但对于一个"启动"的应用程序,即需求会随着时间的推移而发展,并且有多种方法可以在没有复杂验证的情况下检索数据,我会使用管道和过滤器方法.

你的想法是什么?你有没有遇到任何上述方法的问题?有什么建议?

即将开始一个新项目,因此这些类型的考虑因素至关重要.

谢谢您的帮助.

编辑规范模式的澄清

这与规范模式的用法相同.

Specification<Foo> someSpec; // Specification is an abstract class, implementing ISpecification<TEntity> members (And, Or, Not, IsSatisfiedBy).
someSpec = new AllFoosMustHaveABarSpecification(); // Simple class which inherits from Specification<Foo> class, overriding abstract method "IsSatisfiedBy" - which provides the actual business logic.    
ICollection<Foo> foos = fooDataService.GetFoosBySpecification(someSpec);
Run Code Online (Sandbox Code Playgroud)

Hen*_*aya 2

从我的一点经验来看:

  1. 用户需求总是在变化,我不知道为什么我的老板总是允许这种变化。所以+1 到规格
  2. 这里的程序员更像是“体力工人”而不是“知识工人”。你知道……整天打字的人。通过使用规范,我可以确保每个人都“键入”。我的项目的性质支持了这一点。为了同一目的,它需要许多不同的实现。别问我为什么。
  3. 使用可为您提供最高模块化性和灵活性以及可测试性的设计模式。这是一个小故事。
    在一个晴朗的日子,我的朋友告诉我,他写了一个类,使我们能够计算 32 种计算 X 的方法。而且他已经实现了所有这些。呵呵,我认为这真是一个英雄般的编程。他花了几个星期的时间在半夜做这件事。他相信自己是一名优秀的程序员,所以他坚持让每个人都使用他的杰作。
    我们当时并不关心单元测试,所以我们使用了他的杰作。然后发生了什么?代码总是崩溃。嗯,从那时起我就意识到单元测试和模块化是多么重要。