2017-03-01 32 views
0

在我的项目中;我已经包含了下面给出的特定模式类。我不知道如何实现这一点。这些代码由以前的开发人员提供。如何实现规格模式?

public interface ISpecification<T> 
{ 
    Expression<Func<T, bool>> SpecExpression { get; } 
    bool IsSatisfiedBy(T obj); 
} 

public static class IExtensions 
{ 
    public static ISpecification<T> And<T>(
     this ISpecification<T> left, 
     ISpecification<T> right) 
    { 
     return new And<T>(left, right); 
    } 

    public static ISpecification<T> Or<T>(
     this ISpecification<T> left, 
     ISpecification<T> right) 
    { 
     return new Or<T>(left, right); 
    } 

    public static ISpecification<T> Negate<T>(this ISpecification<T> inner) 
    { 
     return new Negated<T>(inner); 
    } 
} 

public abstract class SpecificationBase<T> : ISpecification<T> 
{ 
    private Func<T, bool> _compiledExpression; 

    private Func<T, bool> CompiledExpression 
    { 
     get { return _compiledExpression ?? (_compiledExpression = SpecExpression.Compile()); } 
    } 

    public abstract Expression<Func<T, bool>> SpecExpression { get; } 

    public bool IsSatisfiedBy(T obj) 
    { 
     return CompiledExpression(obj); 
    } 
} 

public class And<T> : SpecificationBase<T> 
{ 
    ISpecification<T> left; 
    ISpecification<T> right; 

    public And(
     ISpecification<T> left, 
     ISpecification<T> right) 
    { 
     this.left = left; 
     this.right = right; 
    } 

    // AndSpecification 
    public override Expression<Func<T, bool>> SpecExpression 
    { 
     get 
     { 
      var objParam = Expression.Parameter(typeof(T), "obj"); 

      var newExpr = Expression.Lambda<Func<T, bool>>(
       Expression.AndAlso(
        Expression.Invoke(left.SpecExpression, objParam), 
        Expression.Invoke(right.SpecExpression, objParam) 
       ), 
       objParam 
      ); 

      return newExpr; 
     } 
    } 
} 

public class Or<T> : SpecificationBase<T> 
{ 
    ISpecification<T> left; 
    ISpecification<T> right; 

    public Or(
     ISpecification<T> left, 
     ISpecification<T> right) 
    { 
     this.left = left; 
     this.right = right; 
    } 

    // OrSpecification 
    public override Expression<Func<T, bool>> SpecExpression 
    { 
     get 
     { 
      var objParam = Expression.Parameter(typeof(T), "obj"); 

      var newExpr = Expression.Lambda<Func<T, bool>>(
       Expression.OrElse(
        Expression.Invoke(left.SpecExpression, objParam), 
        Expression.Invoke(right.SpecExpression, objParam) 
       ), 
       objParam 
      ); 

      return newExpr; 
     } 
    } 
} 

public class Negated<T> : SpecificationBase<T> 
{ 
    private readonly ISpecification<T> _inner; 

    public Negated(ISpecification<T> inner) 
    { 
     _inner = inner; 
    } 

    // NegatedSpecification 
    public override Expression<Func<T, bool>> SpecExpression 
    { 
     get 
     { 
      var objParam = Expression.Parameter(typeof(T), "obj"); 

      var newExpr = Expression.Lambda<Func<T, bool>>(
       Expression.Not(
        Expression.Invoke(this._inner.SpecExpression, objParam) 
       ), 
       objParam 
      ); 

      return newExpr; 
     } 
    } 
} 

如何通过一个简单的例子来实现上述规范?这个规范有什么用处?

+0

这是借助'Expression'实现的规范模式。它的用例取决于你的域模型。 –

+0

@Ofir Winegarten你可以举一个小例子,上面的课程?如何使用它? – Pradees

回答

0

正如我在评论中写的,这是借助Expression实现的规范模式。

比方说,我们有以下域的型号:

public class Person 
{ 
    public string Name { get; set; } 
    public DateTime BirthDate { get; set; } 
    public string Country { get; set; } 
} 

而且,还有,我们有以下列表:

List<Person> persons; // <-- initialized elsewhere 

现在我们可以有两个规范他们。让我们有一个为那些谁住在Spain,一个用于那些以前01/01/2000

public class SpainSpec : SpecificationBase<Person> 
{ 
    public override Expression<Func<Person, bool>> SpecExpression => person => person.Country == "Spain"; 
} 

public class BornBefore2000 : SpecificationBase<Person> 
{ 
    public override Expression<Func<Person, bool>> SpecExpression => person => person.BirthDate < DateTime.Parse("2000-01-01"); 
} 

出生现在,我们可以用它来寻找2000年以前出生的所有人:

ISpecification spec = new SpainSpec(); 
persons.Where (spec.IsSatisfiedBy); 

你可以ofcourse它们链让这些来自西班牙是在2000年以前出生的:

ISpecification spec = new SpainSpec().And(new BornBefore2000()); 
persons.Where (spec.IsSatisfiedBy); 

这的确是一个非常简单的场景,你可以有更多,这取决于你的模型和需求。

使用规格时要小心,以免你失去控制权,并且班级太多或发现自己重新发明了车轮。