Specification pattern: Difference between revisions

Content deleted Content added
m Reverted edits by 80.91.200.89 (talk) to last revision by 2A01:E0A:84B:9950:BD4B:293D:F4F4:D0A: editing tests
No edit summary
Line 14:
 
<syntaxhighlight lang="csharp">
public interface ISpecification
{
bool IsSatisfiedBy(object candidate);
ISpecification And(ISpecification other);
ISpecification AndNot(ISpecification other);
ISpecification Or(ISpecification other);
ISpecification OrNot(ISpecification other);
ISpecification Not();
}
 
public abstract class CompositeSpecification : ISpecification
{
public abstract bool IsSatisfiedBy(object candidate);
 
public ISpecification And(ISpecification other)
{
boolreturn IsSatisfiedBynew AndSpecification(objectthis, candidateother);
ISpecification And(ISpecification other);
ISpecification AndNot(ISpecification other);
ISpecification Or(ISpecification other);
ISpecification OrNot(ISpecification other);
ISpecification Not();
}
 
public ISpecification AndNot(ISpecification other)
public abstract class CompositeSpecification : ISpecification
{
publicreturn abstractnew bool IsSatisfiedByAndNotSpecification(objectthis, candidateother);
 
public ISpecification And(ISpecification other)
{
return new AndSpecification(this, other);
}
 
public ISpecification AndNot(ISpecification other)
{
return new AndNotSpecification(this, other);
}
 
public ISpecification Or(ISpecification other)
{
return new OrSpecification(this, other);
}
 
public ISpecification OrNot(ISpecification other)
{
return new OrNotSpecification(this, other);
}
 
public ISpecification Not()
{
return new NotSpecification(this);
}
}
 
public classISpecification AndSpecificationOr(ISpecification : CompositeSpecificationother)
{
return new OrSpecification(this, other);
private ISpecification leftCondition;
}
private ISpecification rightCondition;
 
public AndSpecification(ISpecification left, OrNot(ISpecification rightother)
{
return new OrNotSpecification(this, other);
leftCondition = left;
rightCondition = right;
}
 
public override bool IsSatisfiedBy(object candidate)
{
return leftCondition.IsSatisfiedBy(candidate) && rightCondition.IsSatisfiedBy(candidate);
}
}
 
public ISpecification Not()
public class AndNotSpecification : CompositeSpecification
{
return new NotSpecification(this);
private ISpecification leftCondition;
}
private ISpecification rightCondition;
}
 
public class AndSpecification : CompositeSpecification
public AndNotSpecification(ISpecification left, ISpecification right)
{
{
private ISpecification leftCondition = left;
private ISpecification rightCondition = right;
}
 
public AndSpecification(ISpecification left, ISpecification right)
public override bool IsSatisfiedBy(object candidate)
{
return leftCondition.IsSatisfiedBy(candidate) && rightCondition.IsSatisfiedBy(candidate) != trueleft;
}rightCondition = right;
}
 
public override bool IsSatisfiedBy(object candidate)
public class OrSpecification : CompositeSpecification
{
private ISpecificationreturn leftCondition.IsSatisfiedBy(candidate) && rightCondition.IsSatisfiedBy(candidate);
}
private ISpecification rightCondition;
}
 
public class AndNotSpecification : CompositeSpecification
public OrSpecification(ISpecification left, ISpecification right)
{
{
private ISpecification leftCondition = left;
private ISpecification rightCondition = right;
}
 
public AndNotSpecification(ISpecification left, ISpecification right)
public override bool IsSatisfiedBy(object candidate)
{
return leftCondition.IsSatisfiedBy(candidate) ||= rightCondition.IsSatisfiedBy(candidate)left;
}rightCondition = right;
}
 
public override bool IsSatisfiedBy(object candidate)
public class OrNotSpecification : CompositeSpecification
{
return leftCondition.IsSatisfiedBy(candidate) && rightCondition.IsSatisfiedBy(candidate) != true;
private ISpecification leftCondition;
}
private ISpecification rightCondition;
}
 
public class OrSpecification : CompositeSpecification
public OrNotSpecification(ISpecification left, ISpecification right)
{
{
private ISpecification leftCondition = left;
private ISpecification rightCondition = right;
}
 
public OrSpecification(ISpecification left, ISpecification right)
public override bool IsSatisfiedBy(object candidate)
{
return leftCondition.IsSatisfiedBy(candidate) || rightCondition.IsSatisfiedBy(candidate) != trueleft;
}rightCondition = right;
}
 
public override bool IsSatisfiedBy(object candidate)
public class NotSpecification : CompositeSpecification
{
return leftCondition.IsSatisfiedBy(candidate) || rightCondition.IsSatisfiedBy(candidate);
private ISpecification Wrapped;
 
public NotSpecification(ISpecification x)
{
Wrapped = x;
}
 
public override bool IsSatisfiedBy(object candidate)
{
return !Wrapped.IsSatisfiedBy(candidate);
}
}
}
 
public class OrNotSpecification : CompositeSpecification
</syntaxhighlight>
{
private ISpecification leftCondition;
private ISpecification rightCondition;
 
public OrNotSpecification(ISpecification left, ISpecification right)
=== [[C Sharp (programming language)|C# 6.0]] with generics ===
 
<syntaxhighlight lang="csharp">
public interface ISpecification<T>
{
boolleftCondition IsSatisfiedBy(T= candidate)left;
rightCondition = right;
ISpecification<T> And(ISpecification<T> other);
ISpecification<T> AndNot(ISpecification<T> other);
ISpecification<T> Or(ISpecification<T> other);
ISpecification<T> OrNot(ISpecification<T> other);
ISpecification<T> Not();
}
 
public override bool IsSatisfiedBy(object candidate)
public abstract class LinqSpecification<T> : CompositeSpecification<T>
{
return leftCondition.IsSatisfiedBy(candidate) || rightCondition.IsSatisfiedBy(candidate) != true;
public abstract Expression<Func<T, bool>> AsExpression();
public override bool IsSatisfiedBy(T candidate) => AsExpression().Compile()(candidate);
}
}
 
public class NotSpecification : CompositeSpecification
{
private ISpecification Wrapped;
 
public NotSpecification(ISpecification x)
public abstract class CompositeSpecification<T> : ISpecification<T>
{
Wrapped = x;
public abstract bool IsSatisfiedBy(T candidate);
public ISpecification<T> And(ISpecification<T> other) => new AndSpecification<T>(this, other);
public ISpecification<T> AndNot(ISpecification<T> other) => new AndNotSpecification<T>(this, other);
public ISpecification<T> Or(ISpecification<T> other) => new OrSpecification<T>(this, other);
public ISpecification<T> OrNot(ISpecification<T> other) => new OrNotSpecification<T>(this, other);
public ISpecification<T> Not() => new NotSpecification<T>(this);
}
 
public override bool IsSatisfiedBy(object candidate)
public class AndSpecification<T> : CompositeSpecification<T>
{
return !Wrapped.IsSatisfiedBy(candidate);
ISpecification<T> left;
}
ISpecification<T> right;
}
</syntaxhighlight>
 
=== [[C Sharp (programming language)|C# 6.0]] with generics ===
public AndSpecification(ISpecification<T> left, ISpecification<T> right)
{
this.left = left;
this.right = right;
}
 
<syntaxhighlight lang="csharp">
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) && right.IsSatisfiedBy(candidate);
public interface ISpecification<T>
}
{
bool IsSatisfiedBy(T candidate);
ISpecification<T> And(ISpecification<T> other);
ISpecification<T> AndNot(ISpecification<T> other);
ISpecification<T> Or(ISpecification<T> other);
ISpecification<T> OrNot(ISpecification<T> other);
ISpecification<T> Not();
}
 
public publicabstract class AndNotSpecificationLinqSpecification<T> : CompositeSpecification<T>
{
{
public abstract Expression<Func<T, bool>> AsExpression();
ISpecification<T> left;
public override bool IsSatisfiedBy(T candidate) => AsExpression().Compile()(candidate);
ISpecification<T> right;
}
 
public abstract class public AndNotSpecification(ISpecificationCompositeSpecification<T> left,: ISpecification<T> right)
{
{
public abstract bool IsSatisfiedBy(T candidate);
this.left = left;
public ISpecification<T> And(ISpecification<T> other) => new AndSpecification<T>(this, other);
this.right = right;
public ISpecification<T> AndNot(ISpecification<T> other) => new AndNotSpecification<T>(this, other);
}
public ISpecification<T> Or(ISpecification<T> other) => new OrSpecification<T>(this, other);
public ISpecification<T> OrNot(ISpecification<T> other) => new OrNotSpecification<T>(this, other);
public ISpecification<T> Not() => new NotSpecification<T>(this);
}
 
public class AndSpecification<T> : CompositeSpecification<T>
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) && !right.IsSatisfiedBy(candidate);
{
}
ISpecification<T> left;
ISpecification<T> right;
 
public class OrSpecificationAndSpecification(ISpecification<T> :left, CompositeSpecificationISpecification<T> right)
{
ISpecification<T>this.left = left;
ISpecification<T>this.right = right;
}
 
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) && right.IsSatisfiedBy(candidate);
public OrSpecification(ISpecification<T> left, ISpecification<T> right)
}
{
this.left = left;
this.right = right;
}
 
public class AndNotSpecification<T> : CompositeSpecification<T>
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) || right.IsSatisfiedBy(candidate);
{
}
ISpecification<T> left;
public class OrNotSpecification<T> : CompositeSpecification<T>
ISpecification<T> right;
 
public AndNotSpecification(ISpecification<T> left, ISpecification<T> right)
{
ISpecification<T>this.left = left;
ISpecification<T>this.right = right;
}
 
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) && !right.IsSatisfiedBy(candidate);
public OrNotSpecification(ISpecification<T> left, ISpecification<T> right)
}
{
this.left = left;
this.right = right;
}
 
public class OrSpecification<T> : CompositeSpecification<T>
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) || !right.IsSatisfiedBy(candidate);
{
ISpecification<T> left;
ISpecification<T> right;
 
public OrSpecification(ISpecification<T> left, ISpecification<T> right)
{
this.left = left;
this.right = right;
}
 
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) || right.IsSatisfiedBy(candidate);
public class NotSpecification<T> : CompositeSpecification<T>
}
public class OrNotSpecification<T> : CompositeSpecification<T>
{
ISpecification<T> left;
ISpecification<T> right;
 
public OrNotSpecification(ISpecification<T> left, ISpecification<T> right)
{
ISpecification<T>this.left other= left;
public NotSpecification(ISpecification<T> other) => this.otherright = otherright;
public override bool IsSatisfiedBy(T candidate) => !other.IsSatisfiedBy(candidate);
}
 
public override bool IsSatisfiedBy(T candidate) => left.IsSatisfiedBy(candidate) || !right.IsSatisfiedBy(candidate);
}
 
public class NotSpecification<T> : CompositeSpecification<T>
{
ISpecification<T> other;
public NotSpecification(ISpecification<T> other) => this.other = other;
public override bool IsSatisfiedBy(T candidate) => !other.IsSatisfiedBy(candidate);
}
</syntaxhighlight>
 
Line 519 ⟶ 518:
This example is meant to show the end result of how the logic is 'chained' together.
 
This usage example assumes a previously defined <code>OverdueSpecification</code> class that is satisfied when an invoice's due date is 30 days or older, a <code>NoticeSentSpecification</code> class that is satisfied when three notices have been sent to the customer, and an <code>InCollectionSpecification</code> class that is satisfied when an invoice has already been sent to the collection agency. The implementation of these classes isn't important here.
 
Using these three specifications, we created a new specification called <code>SendToCollection</code> which will be satisfied when an invoice is overdue, when notices have been sent to the customer, and are not already with the collection agency.
 
<syntaxhighlight lang="csharp">
var OverDueoverDue = new OverDueSpecification();
var NoticeSentnoticeSent = new NoticeSentSpecification();
var InCollectioninCollection = new InCollectionSpecification();
 
// exampleExample of specification pattern logic chaining
var SendToCollectionsendToCollection = OverDueoverDue.And(NoticeSentnoticeSent).And(InCollectioninCollection.Not());
 
var InvoiceCollectioninvoiceCollection = Service.GetInvoices();
 
foreach (var currentInvoice in InvoiceCollectioninvoiceCollection)
{
if (SendToCollectionsendToCollection.IsSatisfiedBy(currentInvoice))
{
currentInvoice.SendToCollection();
}