Created
June 30, 2023 20:48
-
-
Save rootn3rd/91551fb99d683c77393be139a675a233 to your computer and use it in GitHub Desktop.
Specification Pattern Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List<User> list = new() | |
{ | |
new ("Raymond", 14, false), | |
new ("Shayna", 34, true), | |
new ("Vijay",20, false) | |
}; | |
Console.WriteLine("\nSingle Expr--------"); | |
ExpressionSpecification<User> exp = new(u => u.IsGraduated); | |
List<User> singleSpec = list.FindAll(exp.IsSatisfiedBy); | |
singleSpec.ForEach(Console.WriteLine); | |
Console.WriteLine("\nAnd Expr--------"); | |
ExpressionSpecification<User> underAgeSpec = new(u => u.Age > 16); | |
List<User> andSpec = list.FindAll(exp.And(underAgeSpec).IsSatisfiedBy); | |
andSpec.ForEach(Console.WriteLine); | |
Console.WriteLine("\nOr Expr--------"); | |
ExpressionSpecification<User> nameContainNSpec = new(u => u.Name.Contains('n', StringComparison.OrdinalIgnoreCase)); | |
List<User> orSpec = list.FindAll(exp.Or(nameContainNSpec).IsSatisfiedBy); | |
orSpec.ForEach(Console.WriteLine); | |
Console.ReadKey(); | |
record User(string Name, int Age, bool IsGraduated); | |
interface ISpecification<T> | |
{ | |
ISpecification<T> And(ISpecification<T> other); | |
ISpecification<T> Or(ISpecification<T> other); | |
ISpecification<T> Not(ISpecification<T> other); | |
bool IsSatisfiedBy(T obj); | |
} | |
abstract class CompositeSpecification<T> : ISpecification<T> | |
{ | |
public ISpecification<T> And(ISpecification<T> other) => new AndSpecification<T>(this, other); | |
public ISpecification<T> Not(ISpecification<T> other) => new NotSpecification<T>(other); | |
public ISpecification<T> Or(ISpecification<T> other) => new OrSpecification<T>(this, other); | |
public abstract bool IsSatisfiedBy(T obj); | |
} | |
class AndSpecification<T> : CompositeSpecification<T> | |
{ | |
public AndSpecification(ISpecification<T> leftSpec, ISpecification<T> rightSpec) | |
{ | |
Left = leftSpec; | |
Right = rightSpec; | |
} | |
public ISpecification<T> Left { get; } | |
public ISpecification<T> Right { get; } | |
public override bool IsSatisfiedBy(T obj) => Left.IsSatisfiedBy(obj) && Right.IsSatisfiedBy(obj); | |
} | |
class OrSpecification<T> : CompositeSpecification<T> | |
{ | |
public OrSpecification(ISpecification<T> leftSpec, ISpecification<T> rightSpec) | |
{ | |
Left = leftSpec; | |
Right = rightSpec; | |
} | |
public ISpecification<T> Left { get; } | |
public ISpecification<T> Right { get; } | |
public override bool IsSatisfiedBy(T obj) => Left.IsSatisfiedBy(obj) || Right.IsSatisfiedBy(obj); | |
} | |
class NotSpecification<T> : CompositeSpecification<T> | |
{ | |
public NotSpecification(ISpecification<T> other) => Other = other; | |
public ISpecification<T> Other { get; } | |
public override bool IsSatisfiedBy(T obj) => !Other.IsSatisfiedBy(obj); | |
} | |
class ExpressionSpecification<T> : CompositeSpecification<T> | |
{ | |
public ExpressionSpecification(Func<T, bool> expression) => Expression = expression; | |
public Func<T, bool> Expression { get; } | |
public override bool IsSatisfiedBy(T obj) => Expression(obj); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment