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

关于Specification

首先我们来看常见的Specification模式中的类图(来自于http://en.wikipedia.org/wiki/Specification_pattern):

Specification,规格说明书,这里我们可以理解为规则约束,我们可以对每个规则定义一个Specification,同时也可以将不同的Specification进行组合使用。

简单实现

首先我们定义ISpecification接口:

public interface ISpecification<T>
{bool IsSatisfiedBy(T candidate);
}

我们定义ICompsiteSpecification,这里使用了Compsite模式(组合模式)

public interface ICompsiteSpecification<T>:ISpecification<T>
{ISpecification<T> Add(ISpecification<T> other);ISpecification<T> Or(ISpecification<T> other);ISpecification<T> Not();
}

AddSpecification:

public class AddSpecification<T>:ISpecification<T>
{private ISpecification<T> _Left;private ISpecification<T> _Right;public AddSpecification(ISpecification<T> left,ISpecification<T> right){_Left = left;_Right = right;}public bool IsSatisfiedBy(T candidate){return _Left.IsSatisfiedBy(candidate) && _Right.IsSatisfiedBy(candidate);}
}

OrSpecification:

public class OrSpecification<T>:ISpecification<T>
{private ISpecification<T> _Left;private ISpecification<T> _Right;public OrSpecification(ISpecification<T> left, ISpecification<T> right){_Left = left;_Right = right;}public bool IsSatisfiedBy(T candidate){return _Left.IsSatisfiedBy(candidate) || _Right.IsSatisfiedBy(candidate);}
}

NoSpecification:

public class NotSpecification<T>:ISpecification<T>
{private ISpecification<T> _Wrapped;public NotSpecification(ISpecification<T> wrapped){_Wrapped = wrapped;}public bool IsSatisfiedBy(T candidate){return (!_Wrapped.IsSatisfiedBy(candidate));}
}

CompositeSpecification:

public abstract class CompositeSpecification<T>:ICompsiteSpecification<T>
{public abstract bool IsSatisfiedBy(T candidate);public ISpecification<T> Add(ISpecification<T> other){return new AddSpecification<T>(this, other);}public ISpecification<T> Or(ISpecification<T> other){return new OrSpecification<T>(this, other);}public ISpecification<T> Not(){return new NotSpecification<T>(this);}
}

我们举了个实际的例子进行使用,比如我们要获取一个数组里面所有的大于0而且是偶数的数字。这个时候我们可以定义两个Specification,一个是整数的Specification,一个是偶数的Specification:

public class EvenSpecification:CompositeSpecification<int>
{public override bool IsSatisfiedBy(int candidate){return candidate % 2 == 0;}
}

我们再定义一个判断为正数的Specification:

public class PositiveSpecification:CompositeSpecification<int>
{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<T>
{Expression<Func<T, bool>> IsSatisfiedBy();
}

在这里IsSatisfiedBy方法返回的不是bool类型的,而是返回一个Lambda表达式,是为了跟Where进行配合使用。

这个时候我们对Expression<Func<T,bool>>类型进行扩展增加其And、Or方法:

public static class ExpressionBuilder
{public static Expression<T> Compose<T>(this Expression<T> left,Expression<T> right,Func<Expression, Expression, Expression> 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<T>(merge(left, rightBody), left.Parameters);}public static Expression<Func<T,bool>> And<T>(this Expression<Func<T,bool>> left,Expression<Func<T,bool>> right){return left.Compose(right, Expression.Add);}public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right){return left.Compose(right, Expression.Or);}
}

Visitor:

public class ParameterRebinder:ExpressionVisitor
{private readonly Dictionary<ParameterExpression, ParameterExpression> _Map;public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> 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<ParameterExpression, ParameterExpression> map, Expression exp){return (new ParameterRebinder(map)).Visit(exp);}
}

上面的扩展为了我们方便的实现Expression<Func<T,bool>>类型进行我们逻辑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<T>:ISpecification<T>
{public abstract Expression<Func<T, bool>> IsSatisfiedBy();public static ISpecification<T> operator |(Specification<T> left, Specification<T> right){return new OrSpecification<T>(left, right);}public static ISpecification<T> operator &(Specification<T> left, Specification<T> right){return new AddSpecification<T>(left, right);}public static ISpecification<T> operator !(Specification<T> specification){return new NotSpecification<T>(specification);}public static bool operator false(Specification<T> specification){return false;}public static bool operator true(Specification<T> specification){return true;}
}

CompositeSpecification:

public abstract class CompositeSpecification<T>:Specification<T>
{public abstract ISpecification<T> Left { get; }public abstract ISpecification<T> Right { get; }}

And:

public class AddSpecification<T>:CompositeSpecification<T>
{private ISpecification<T> _Left;private ISpecification<T> _Right;public AddSpecification(ISpecification<T> left,ISpecification<T> right){_Left = left;_Right = right;}public override ISpecification<T> Left{get { return _Left; }}public override ISpecification<T> Right{get { return _Right; }}public override Expression<Func<T,bool>> IsSatisfiedBy(){return _Left.IsSatisfiedBy().And(_Right.IsSatisfiedBy());}
}

Or:

public class OrSpecification<T> : CompositeSpecification<T>
{private ISpecification<T> _Left;private ISpecification<T> _Right;public OrSpecification(ISpecification<T> left, ISpecification<T> right){_Left = left;_Right = right;}public override ISpecification<T> Left{get { return _Left; }}public override ISpecification<T> Right{get { return _Right; }}public override Expression<Func<T, bool>> IsSatisfiedBy(){return _Left.IsSatisfiedBy().Or(_Right.IsSatisfiedBy());}}

Not:

public class NotSpecification<T>:Specification<T>
{private ISpecification<T> _Wrapped;public NotSpecification(ISpecification<T> wrapped){_Wrapped = wrapped;}public override Expression<Func<T,bool>> IsSatisfiedBy(){return Expression.Lambda<Func<T, bool>>(Expression.Not(_Wrapped.IsSatisfiedBy().Body),_Wrapped.IsSatisfiedBy().Parameters.Single());}
}

其实我们上面的实现的类图是这样的一种结构:

举个例子,比如我们在实际的查询中,可以定义自己的Specification,同时可以通过And、Or进行查询规则的组合,然后传递给Repository.

总结

本文中主要讲解了Specification模式,以及我们在项目中如何使用Specification的。希望对您有用。

作者:Henllyee Cui
出处: http://henllyee.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。

转载于:https://www.cnblogs.com/Henllyee/archive/2011/09/12/Specification.html

DDD中的Specification模式相关推荐

  1. DDD中的建模方法有哪些

    一.背景 在之前的文章中已经介绍了DDD相关的概念模式,DDD相关的业务技术架构,但是我们还没有找到一个核心的抓手去实践DDD.DDD的一个核心本质就是对业务建模,或者领域建模.说的很简单,但是做好确 ...

  2. 聊一聊DDD中聚合的概念

    DDD中的聚合模式是最难弄清楚的一种模式,在如何确定聚合边界这个问题上,更没有一个明确的指导原则,这导致DDD的落地比较难.不过,相信你读了这篇文章应该对聚合会有更深刻的理解. 本文分三部分来讲: 1 ...

  3. ddd模型的pom版本怎么管理_DDD 中的那些模式 — CQRS

    DDD 作为一种系统分析的方法论,最大的问题是如何在项目中实践.而在实践过程中必然会面临许多的问题,「模式」是系统架构领域中一种常见的手段,能够帮助开发人员与架构师在遭遇某种较为棘手,或是陌生的问题时 ...

  4. 趣味编程:C#中Specification模式的实现(参考答案 - 下)

    上一篇文章中我们利用C#语言的特性实现了一种轻量级的Specification模式,它的关键在于抛弃了具体的Specification类型,而是使用一个委托对象代替唯一关键的IsSatisfiedBy ...

  5. 趣味编程:C#中Specification模式的实现

    今天有朋友在问了我这么一个问题:怎么实现OrWhere的功能?我猜测,他的意思是要实现这样的功能: static IEnumerable<int> MorePredicate(IEnume ...

  6. ASP.NET Core 中的规约模式(Specification Pattern )——增强泛型仓储模式

    原文链接:https://codewithmukesh.com/blog/specification-pattern-in-aspnet-core/ 在本文中,我们将讨论在 ASP.NET Core ...

  7. 这 3 种 DDD 分层架构的模式,你掌握了么?

    -     前言    - 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. -     DDD 的基本概念     - DDD(Domain DrivenDesign, ...

  8. MVC架构中的Repository模式 个人理解

    关于MVC架构中的Repository模式 个人理解:Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间.它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提 ...

  9. java jpa 规范_Java:在JPA中使用规范模式

    java jpa 规范 本文是在Java中使用规范模式的简介. 我们还将看到如何将经典规范与JPA Criteria查询结合使用,以从关系数据库中检索对象. 在本文中,我们将使用以下Poll类作为创建 ...

  10. 领域驱动设计模式设计与实践_在域驱动设计中使用状态模式

    领域驱动设计模式设计与实践 域驱动设计(DDD)是一种开发软件的方法,其中,通过将实现与核心业务概念的不断发展的模型相联系,解决了问题的复杂性. 该术语是由Eric Evans创造的,并且有一个DDD ...

最新文章

  1. java 跳转action_JS 跳转到指定Action | 学步园
  2. 粒子文字特效css,CSS3 粒子效果
  3. 需求分析——掌握UML建模语言的用例图
  4. 一文掌握常用的机器学习模型(免费课程+送书福利)
  5. oracle 函数可变参数,6.3 带有可变参数的函数
  6. nginx 编译出现的问题ngx_murmurhash.o failed
  7. Java多线程知识点整理(Lock锁)
  8. SubLime Text 3 的常用插件
  9. bat脚本重启IIS中的网站
  10. 不同浏览器的使用体会
  11. Android支付宝刷步数,蚂蚁森林刷步数小技巧(一键修改支付宝步数)
  12. 《2022女程序员人群洞察报告》
  13. 《Investigating Typed Syntactic Dependencies for TSC Using GAT》论文笔记
  14. Android面试总结(持续更新修改)
  15. 图论(2):树和割集
  16. 完全背包问题(师从yxc,闫氏Dp)
  17. 网工知识角|例行维护检查华为设备,这10个常用命令你必须掌握
  18. java如何比较两个date_在Java中,如何获得两个date之间的差异秒?
  19. ROS2源码快捷下载的办法
  20. NM网络管理dbc中信号属性

热门文章

  1. Solr 4.10.3 后台管理页面介绍
  2. phpstudy配置域名后apache无法启动
  3. 通过try、except和else的使用来使Python程序更加“强壮”
  4. P2326 AKN’s PPAP
  5. appserv+win8
  6. 代码审查(咳咳......又降温了啊....!!!!)
  7. (转)Linux命令grep
  8. verilog 之数字电路 边沿检测电路
  9. 剖析WordPress模板文件【转】
  10. 详解Android核心模块及相关技术