2017-03-01 50 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); 

這的確是一個非常簡單的場景,你可以有更多,這取決於你的模型和需求。

使用規格時要小心,以免你失去控制權,並且班級太多或發現自己重新發明了車輪。