【发布时间】:2010-08-26 23:51:17
【问题描述】:
我正在做一些研发工作,因此正在探索设计模式。我最近一直在阅读规范模式,并被提及 this 很棒的文章。
我对代码的简洁性和简洁性很感兴趣,但我开始对使用其他技术实现相同的简洁性进行比较。
考虑以下服务层的接口契约:
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();
}
实施要点:
- 这三者的实现都极其简单(一行代码)
- 在外部实施过滤的规范和搜索参数。
- Search args 方法只是使用 IEnumerable 扩展方法来检查 args
那么,话虽如此,在什么情况下您会使用上述 3 种技术中的一种?
我对规范模式的看法:
- 很好,因为它将业务/域需求隔离到可重用的组件中
- 非常容易阅读,让代码说英语
- 涉及相当多的代码(接口、抽象类)。如果我要使用它,我会将抽象放在一个通用程序集中(所以我的解决方案中没有一堆静态文件)。
- 只需更改规范而不是服务层即可轻松更改需求。
- 领域逻辑的最高可测试性(规范)
我对扩展方法(管道和过滤器)的看法:
- 逻辑上的“重量级”,但仍然具有相同的简单性。
- 将查询逻辑从服务层隔离到静态方法
- 仍然需要排序的“反射”(检查提供的搜索参数并构建查询)
- 允许您首先对架构(存储库、服务层)进行编码,而无需考虑特定的业务需求(这在某些场景中很方便)
我对谓词方法的看法:
- 可用于需要对查询进行粗粒度控制的情况。
- 适用于规范可能过度的小型项目
我最后的思考逻辑是,如果您正在开发一个复杂的业务应用程序,其中业务需求预先知道但可能会随着时间而改变,那么我会使用规范模式。
但是对于一个“启动”的应用程序,即需求会随着时间的推移而发展,并且有多种方法可以在没有复杂验证的情况下检索数据,我会使用 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);
【问题讨论】:
-
不完全清楚
Specification<Foo>与Func<Foo, bool>有何不同。 -
@Gabe - 我不想发布关于规范模式是如何实现的代码,因为 a) 它有很多代码(4 个类)和 b) 我提供的链接提供了实现细节。
-
我阅读了链接;我只是看不出语义上的差异。
-
@Gabe,那么您显然不了解规范模式。 Func
表示您传入一个lamba谓词 - 即 .GetFoosByPredicate(f => f.Bar = "FooBar");规范是满足属性封装在方法(IsSatisfiedBy)中的特定对象。 -
所以你可以写
.GetFoosByPredicate(f => f.Bar = "FooBar")或.GetFoosBySpecification(new Specification<Foo>(f => f.Bar = "FooBar"))?我看不出这能带给你什么。一种方式是否比另一种方式更具表现力?一个更容易使用吗?快点?提供更好的抽象?
标签: design-patterns architecture extension-methods specification-pattern pipes-filters