2017-03-01 6 views
0

In meinem Projekt; Ich habe spezifische Musterklassen eingeschlossen, die unten angegeben sind. Ich weiß nicht, wie ich das umsetzen soll. Diese Codes sind von früheren Entwicklern enthalten.Wie wird das Spezifikationsmuster implementiert?

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; 
     } 
    } 
} 

Wie die obige Spezifikation mit einem einfachen Beispiel implementieren? Was nützt diese Spezifikation?

+0

Dies ist das Spezifikationsmuster, das mit Hilfe von "Expression" implementiert wurde. Der Anwendungsfall dafür hängt von Ihrem Domänenmodell ab. –

+0

@Ofir Winegarten Kannst du ein kleines Beispiel mit obigen Klassen geben? Wie man es benutzt? – Pradees

Antwort

0

Wie ich in den Kommentaren schrieb, ist dies die Spezifikation Muster mit Hilfe von Expression implementiert.

Lassen Sie uns sagen, dass wir die folgenden Domain-Modell haben:

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

Und auch, haben wir eine Liste dieser:

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

Jetzt können wir für sie zwei Spezifikation haben. Lässt eine solche für die in Spain und eine für jene, die vor 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"); 
} 

Jetzt können wir es geboren leben diejenigen, die verwenden, um alle Personen, die vor 2000 geboren zu finden:

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

Sie können sie natürlich die Kette zu diejenigen, die aus Spanien erhalten, die vor 2000 geboren wurden:

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

Das ist wirklich ein sehr einfaches Szenario, das Sie viele mehr, je nach Modell Sie und Bedürfnisse haben.

Seien Sie vorsichtig, wenn Sie Spezifikationen verwenden, damit Sie nicht die Kontrolle darüber verlieren und zu viele Klassen haben oder sich das Rad neu erfinden.

Verwandte Themen