DDD中的Specification模式

在领域驱动开发中,我们会常用到Repository、Unit of Work等模式,而Specification模式并不是很常用,Specification模式在领域层中主要为我们实现领域规则的自由组合。

关于Specification

首先我们来看常见的Specification模式中的类图(来自于http://en.wikipedia.org/wiki/Specification_pattern):
Specification_UMLDDD中的Specification模式
Specification,规格说明书,这里我们可以理解为规则约束,我们可以对每个规则定义一个Specification,同时也可以将不同的Specification进行组合使用。

简单实现

首先我们定义ISpecification接口:
public interface ISpecification { bool IsSatisfiedBy(T candidate); }
我们定义ICompsiteSpecification,这里使用了Compsite模式(组合模式)
public interface ICompsiteSpecification:ISpecification { ISpecification Add(ISpecification other); ISpecification Or(ISpecification other); ISpecification Not(); }
AddSpecification:
public class AddSpecification:ISpecification { private ISpecification _Left; private ISpecification _Right; public AddSpecification(ISpecification left,ISpecification right) { _Left = left; _Right = right; } public bool IsSatisfiedBy(T candidate) { return _Left.IsSatisfiedBy(candidate) && _Right.IsSatisfiedBy(candidate); } }
OrSpecification:
public class OrSpecification:ISpecification { private ISpecification _Left; private ISpecification _Right; public OrSpecification(ISpecification left, ISpecification right) { _Left = left; _Right = right; } public bool IsSatisfiedBy(T candidate) { return _Left.IsSatisfiedBy(candidate) || _Right.IsSatisfiedBy(candidate); } }
NoSpecification:
public class NotSpecification:ISpecification { private ISpecification _Wrapped; public NotSpecification(ISpecification wrapped) { _Wrapped = wrapped; } public bool IsSatisfiedBy(T candidate) { return (!_Wrapped.IsSatisfiedBy(candidate)); } }
CompositeSpecification:
public abstract class CompositeSpecification:ICompsiteSpecification { public abstract bool IsSatisfiedBy(T candidate); public ISpecification Add(ISpecification other) { return new AddSpecification(this, other); } public ISpecification Or(ISpecification other) { return new OrSpecification(this, other); } public ISpecification Not() { return new NotSpecification(this); } }
我们举了个实际的例子进行使用,比如我们要获取一个数组里面所有的大于0而且是偶数的数字。这个时候我们可以定义两个Specification,一个是整数的Specification,一个是偶数的Specification:
public class EvenSpecification:CompositeSpecification { public override bool IsSatisfiedBy(int candidate) { return candidate % 2 == 0; } }
我们再定义一个判断为正数的Specification:
public class PositiveSpecification:CompositeSpecification { public override bool IsSatisfiedBy(int candidate) { return candidate > 0; } }
使用:
static void Main(string[] args) { var numbers = Enumerable.Range(-10,20); var postivieSpecification = new PositiveSpecification(); var compositSpecification = postivieSpecification.Add(new EvenSpecification()); foreach (var item in numbers.Where(i => compositSpecification.IsSatisfiedBy(i))) { Console.WriteLine(item); } Console.ReadKey(); }

DDD中使用

举个在我们实际业务中的查询来说明下吧。在.net 3.0之后我们有了Lambda表达式,我们可以通过更为优雅的一种方式来实现了:
public interface ISpecification { Expression> IsSatisfiedBy(); }
在这里IsSatisfiedBy方法返回的不是bool类型的,而是返回一个Lambda表达式,是为了跟Where进行配合使用。
这个时候我们对Expression>类型进行扩展增加其And、Or方法:
public static class ExpressionBuilder { public static Expression Compose(this Expression left,Expression right,Func merge) { var params1 = left.Parameters; var params2 = right.Parameters; var map = params1.Select((p,i)=> new {p,s= params2[i]}).ToDictionary(p=>p.s,p=>p.p); var rightBody = ParameterRebinder.ReplaceParameters(map,right.Body); return Expression.Lambda(merge(left, rightBody), left.Parameters); } public static Expression> And(this Expression> left,Expression> right) { return left.Compose(right, Expression.Add); } public static Expression> Or(this Expression> left, Expression> right) { return left.Compose(right, Expression.Or); } }
Visitor:
public class ParameterRebinder:ExpressionVisitor { private readonly Dictionary _Map; public ParameterRebinder(Dictionary map) { _Map = map; } protected override Expression VisitParameter(ParameterExpression node) { ParameterExpression replacement; if (_Map.TryGetValue(node,out replacement)) { node = replacement; } return base.VisitParameter(node); } public static Expression ReplaceParameters(Dictionary map, Expression exp) { return (new ParameterRebinder(map)).Visit(exp); } }
上面的扩展为了我们方便的实现Expression>类型进行我们逻辑And、Or操作。对于表达式书不太熟悉的同学可以参考MSDN上面的两篇文章:http://msdn.microsoft.com/zh-cn/library/bb397951.aspx、http://msdn.microsoft.com/zh-cn/library/bb546136.aspx
为了方便我们进行And、Or动作,我们可以对操作符进行重载:
public abstract class Specification:ISpecification { public abstract Expression> IsSatisfiedBy(); public static ISpecification operator |(Specification left, Specification right) { return new OrSpecification(left, right); } public static ISpecification operator &(Specification left, Specification right) { return new AddSpecification(left, right); } public static ISpecification operator !(Specification specification) { return new NotSpecification(specification); } public static bool operator false(Specification specification) { return false; } public static bool operator true(Specification specification) { return true; } }
CompositeSpecification:
public abstract class CompositeSpecification:Specification { public abstract ISpecification Left { get; } public abstract ISpecification Right { get; } }
And:
public class AddSpecification:CompositeSpecification { private ISpecification _Left; private ISpecification _Right; public AddSpecification(ISpecification left,ISpecification right) { _Left = left; _Right = right; } public override ISpecification Left { get { return _Left; } } public override ISpecification Right { get { return _Right; } } public override Expression> IsSatisfiedBy() { return _Left.IsSatisfiedBy().And(_Right.IsSatisfiedBy()); } }
Or:
public class OrSpecification : CompositeSpecification { private ISpecification _Left; private ISpecification _Right; public OrSpecification(ISpecification left, ISpecification right) { _Left = left; _Right = right; } public override ISpecification Left { get { return _Left; } } public override ISpecification Right { get { return _Right; } } public override Expression> IsSatisfiedBy() { return _Left.IsSatisfiedBy().Or(_Right.IsSatisfiedBy()); } }
Not:
public class NotSpecification:Specification { private ISpecification _Wrapped; public NotSpecification(ISpecification wrapped) { _Wrapped = wrapped; } public override Expression> IsSatisfiedBy() { return Expression.Lambda>(Expression.Not(_Wrapped.IsSatisfiedBy().Body), _Wrapped.IsSatisfiedBy().Parameters.Single()); } }
其实我们上面的实现的类图是这样的一种结构:
imageSpecification_UMLDDD中的Specification模式
举个例子,比如我们在实际的查询中,可以定义自己的Specification,同时可以通过And、Or进行查询规则的组合,然后传递给Repository.

总结

本文中主要讲解了Specification模式,以及我们在项目中如何使用Specification的。希望对您有用。
imageSpecification_UMLDDD中的Specification模式
作者:Henllyee Cui 出处: http://henllyee.cnblogs.com/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。
Tags: 

延伸阅读

最新评论

发表评论