惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
W
WeLiveSecurity
Stack Overflow Blog
Stack Overflow Blog
L
LangChain Blog
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
Google DeepMind News
Google DeepMind News
F
Full Disclosure
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Register - Security
The Register - Security
G
Google Developers Blog
C
Check Point Blog
GbyAI
GbyAI
A
About on SuperTechFans
V
Vulnerabilities – Threatpost
T
The Blog of Author Tim Ferriss
T
Tor Project blog
AWS News Blog
AWS News Blog
Cyberwarzone
Cyberwarzone
C
CERT Recently Published Vulnerability Notes
MongoDB | Blog
MongoDB | Blog
Latest news
Latest news
aimingoo的专栏
aimingoo的专栏
U
Unit 42
Y
Y Combinator Blog
P
Privacy International News Feed
Cisco Talos Blog
Cisco Talos Blog
S
Securelist
S
Schneier on Security
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Attack and Defense Labs
Attack and Defense Labs
P
Proofpoint News Feed
C
Cisco Blogs
Webroot Blog
Webroot Blog
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
月光博客
月光博客
P
Privacy & Cybersecurity Law Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
罗磊的独立博客
Cloudbric
Cloudbric
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Hacker News: Ask HN
Hacker News: Ask HN
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Security Blog
Microsoft Security Blog

博客园 - Henry Cui

招聘高级.Net工程师 Node.js Web开发(二)认识Express(上) Node.js Web开发(一)从零开始 Html5 Step by Step(二) 本地存储 HTML 5 Step by Step(一) 拖放API Git学习笔记(一)初识Git Silverlight 4之旅(三)数据绑定(中) Silverlight 4之旅(二)数据绑定(上) Silverlight 4之旅(一) .Net 4.0 Parallel 编程之旅 .Net 4.0 Parallel 编程(九)Task中的数据共享(下) .Net 4.0 Parallel编程(八)Task中的数据共享(中) .Net 4.0 Parallel 编程(七)Task中的数据共享(上) .Net 4.0 Parallel 编程(六)Task(下) .Net 4.0 Parallel 编程(五)Task(中) .Net 4.0 Parallel 编程(四) Task(上) Entity Framework Code-First(下) Entity Framework Code-First(上) Entity Framework POCO T4模板使用
DDD中的Specification模式
Henry Cui · 2011-09-12 · via 博客园 - Henry Cui

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

关于Specification

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

Specification_UML

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.aspxhttp://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());
    }
}

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

image

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

总结

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