Specification pattern
Encyclopedia
In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic.

A specification pattern outlines a business rule that is combinable with other business rules. In this pattern, a unit of business logic inherits its functionality from the abstract aggregate Composite Specification class. The Composite Specification class has one function called IsSatisfiedBy that returns a boolean value. After instantiation, the specification is "chained" with other specifications, making new specifications easily maintainable, yet highly customizable business logic. Furthermore upon instantiation the business logic may, through method invocation or inversion of control
Inversion of Control
In software engineering, Inversion of Control is an abstract principle describing an aspect of some software architecture designs in which the flow of control of a system is inverted in comparison to procedural programming....

, have its state altered in order to become a delegate of other classes such as a persistence repository.

C# 


public interface ISpecification {
bool IsSatisfiedBy(object candidate);
ISpecification And(ISpecification other);
ISpecification Or(ISpecification other);
ISpecification Not;
}

public abstract class CompositeSpecification : ISpecification {
public abstract bool IsSatisfiedBy(object candidate);

public ISpecification And(ISpecification other) {
return new AndSpecification(this, other);
}

public ISpecification Or(ISpecification other) {
return new OrSpecification(this, other);
}

public ISpecification Not {
return new NotSpecification(this);
}
}

public class AndSpecification : CompositeSpecification {
private ISpecification One;
private ISpecification Other;

public AndSpecification(ISpecification x, ISpecification y) {
One = x;
Other = y;
}

public override bool IsSatisfiedBy(object candidate) {
return One.IsSatisfiedBy(candidate) && Other.IsSatisfiedBy(candidate);
}
}

public class OrSpecification : CompositeSpecification {
private ISpecification One;
private ISpecification Other;

public OrSpecification(ISpecification x, ISpecification y) {
One = x;
Other = y;
}

public override bool IsSatisfiedBy(object candidate) {
return One.IsSatisfiedBy(candidate) || Other.IsSatisfiedBy(candidate);
}
}

public class NotSpecification : CompositeSpecification {
private ISpecification Wrapped;

public NotSpecification(ISpecification x) {
Wrapped = x;
}

public override bool IsSatisfiedBy(object candidate) {
return !Wrapped.IsSatisfiedBy(candidate);
}
}


C# 3.0, simplified with generics and extension methods


public interface ISpecification {
bool IsSatisfiedBy(TEntity entity);
}

internal class AndSpecification : ISpecification {
private ISpecification Spec1;
private ISpecification Spec2;

internal AndSpecification(ISpecification s1, ISpecification s2) {
Spec1 = s1;
Spec2 = s2;
}

public bool IsSatisfiedBy(TEntity candidate) {
return Spec1.IsSatisfiedBy(candidate) && Spec2.IsSatisfiedBy(candidate);
}
}

internal class OrSpecification : ISpecification {
private ISpecification Spec1;
private ISpecification Spec2;

internal OrSpecification(ISpecification s1, ISpecification s2) {
Spec1 = s1;
Spec2 = s2;
}

public bool IsSatisfiedBy(TEntity candidate) {
return Spec1.IsSatisfiedBy(candidate) || Spec2.IsSatisfiedBy(candidate);
}
}

internal class NotSpecification : ISpecification {
private ISpecification Wrapped;

internal NotSpecification(ISpecification x) {
Wrapped = x;
}

public bool IsSatisfiedBy(TEntity candidate) {
return !Wrapped.IsSatisfiedBy(candidate);
}
}

public static class ExtensionMethods {
public static ISpecification And(this ISpecification s1, ISpecification s2) {
return new AndSpecification(s1, s2);
}

public static ISpecification Or(this ISpecification s1, ISpecification s2) {
return new OrSpecification(s1, s2);
}

public static ISpecification Not(this ISpecification s) {
return new NotSpecification(s);
}
}

Example of use

In this example, we are retrieving invoices and sending them to a collection agency if they are overdue, notices have been sent and they are not already with the collection agency.

We previously defined an OverdueSpecification class that it is satisfied when an invoice's due date is 30 days or older, a NoticeSentSpecification class that is satisfied when three notices have been sent to the customer, and an InCollectionSpecification class that is satisfied when an invoice has already been sent to the collection agency.

Using these three specifications, we created a new specification called SendToCollection 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.


OverDueSpecification OverDue = new OverDueSpecification;
NoticeSentSpecification NoticeSent = new NoticeSentSpecification;
InCollectionSpecification InCollection = new InCollectionSpecification;

ISpecification SendToCollection = OverDue.And(NoticeSent).And(InCollection.Not);

InvoiceCollection = Service.GetInvoices;

foreach (Invoice currentInvoice in InvoiceCollection) {
if (SendToCollection.IsSatisfiedBy(currentInvoice)) {
currentInvoice.SendToCollection;
}
}

External links

The source of this article is wikipedia, the free encyclopedia.  The text of this article is licensed under the GFDL.
 
x
OK