我正在做一些研发工作,因此正在探索设计模式。我最近一直在阅读规范模式,并提到了这篇很棒的文章。
我对代码的简洁性和简洁性很感兴趣,但我开始对使用其他技术实现相同的简洁性进行一些比较。
考虑以下服务层的接口契约:
public interface IFooDataService
{
ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification);
ICollection<Foo> GetFooByPredicate(Func<Foo,bool> predicate);
ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs);
}
所以,一些初始点:
- 所有三个都返回 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();
}
实施要点:
- 这三个在实现上都非常简单(一行链式代码)
- 规范和搜索参数过滤在外部实现。
- 搜索 args 方法只是使用 IEnumerable 扩展方法来检查 args
那么,话虽如此,在什么条件下您会使用上述三种技术中的一种?
我对规范模式的看法:
- 很好,因为它将业务/域需求隔离到可重用的组件中
- 非常容易阅读,让代码说英语
- 涉及相当多的代码(接口、抽象类)。如果我要使用它,我会将抽象放在一个通用程序集中(所以我的解决方案中没有一堆静态文件)。
- 只需更改规范而不是服务层即可轻松更改需求。
- 领域逻辑的最高可测试性(规范)
我对扩展方法(管道和过滤器)的看法:
- 逻辑上的“重量级”,但仍然具有相同的简单性。
- 将查询逻辑从服务层隔离到静态方法
- 仍然需要排序的“反射”(检查提供的搜索参数并建立查询)
- 允许您首先对架构(存储库、服务层)进行编码,而无需考虑特定的业务需求(在某些场景中很方便)
我对谓词方法的看法:
- 可用于您需要对查询进行粗粒度控制的地方。
- 适用于规格可能过度的小型项目
我最终的思考逻辑是,如果您正在处理一个复杂的业务应用程序,其中业务需求是预先知道的,但可能会随着时间的推移而改变,那么我会使用规范模式。
但是对于一个“启动”的应用程序,即需求会随着时间的推移而发展,并且有多种方法可以在没有复杂验证的情况下检索数据,我会使用 Pipes 和 Filters 方法。
你怎么认为?你们中的任何人在使用上述任何方法时遇到过问题吗?有什么建议吗?
即将开始一个新项目,因此这些类型的考虑因素至关重要。
谢谢您的帮助。
编辑以澄清规范模式
这是规范模式的相同用法。
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);