Welcome

首页 / 软件开发 / .NET编程技术 / EntityFramework之领域驱动设计实践(十):规约(Specification)模式

EntityFramework之领域驱动设计实践(十):规约(Specification)模式2012-02-09 博客园 dax.net本来针对规约模式的讨论,我并没有想将其列入本系列文章,因为这是一种概念性的东西,从理论上讲,与EntityFramework好像扯不上关系。但应广大网友的要求,我决定还是在这里讨论一下规约模式,并介绍一种专门针对.NET Framework的规约模式实现。

很多时候,我们都会看到类似下面的设计:

Customer仓储的一种设计

public interface ICustomerRespository
{
Customer GetByName(string name);
Customer GetByUserName(string userName);
IList<Customer> GetAllRetired();
}

接下来的一步就是实现这个接口,并在类中分别实现接口中的方法。很明显,在这个接口中,Customer仓储一共做了三个操作:通过姓名获取客户信息;通过用户名获取客户信息以及获得所有当前已退休客户的信息。这样的设计有一个好处就是一目了然,能够很方便地看到Customer仓储到底提供了哪些功能。文档化的开发方式特别喜欢这样的设计。

还是那句话,应需而变。如果你的系统很简单,并且今后扩展的可能性不大,那么这样的设计是简洁高效的。但如果你正在设计一个中大型系统,那么,下面的问题就会让你感到困惑:

这样的设计,便于扩展吗?今后需要添加新的查询逻辑,结果一大堆相关代码都要修改,怎么办?

随着时间的推移,这个接口会变得越来越大,团队中你一榔头我一棒子地对这个接口进行修改,最后整个设计变得一团糟

GetByName和GetByUserName都OK,因为语义一目了然。但是GetAllRetired呢?什么是退休?超过法定退休年龄的算退休,那么病退的是不是算在里面?这里返回的所有Customer中,仅仅包含了已退休的男性客户,还是所有性别的客户都在里面?

规约模式就是DDD引入用来解决以上问题的一种特殊的模式。规约是一种布尔断言,它表述了给定的对象是否满足当前约定的语义。经典的规约模式实现中,规约类只有一个方法,就是IsSatisifedBy(object);如下:

规约

public class Specification
{
public virtual bool IsSatisifedBy(object obj)
{
return true;
}
}