Specification pattern

Short description: Software design pattern

Specification Pattern in UML

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. The pattern is frequently used in the context of domain-driven design.

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, have its state altered in order to become a delegate of other classes such as a persistence repository.

As a consequence of performing runtime composition of high-level business/domain logic, the Specification pattern is a convenient tool for converting ad-hoc user search criteria into low level logic to be processed by repositories.

Since a specification is an encapsulation of logic in a reusable form it is very simple to thoroughly unit test, and when used in this context is also an implementation of the humble object pattern.

## Contents

* 1 Code examples
* 1.1 C#
* 1.2 C# 6.0 with generics
* 1.3 Python
* 1.4 C++
* 1.5 TypeScript
* 2 Example of use
* 3 References
* 4 External links

## Code examples

### C#

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)

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 class AndSpecification : CompositeSpecification

private ISpecification _leftCondition;
private ISpecification _rightCondition;

public AndSpecification(ISpecification left, ISpecification right)

_leftCondition = left;
_rightCondition = right;

public override bool IsSatisfiedBy(object candidate)

return _leftCondition.IsSatisfiedBy(candidate) && _rightCondition.IsSatisfiedBy(candidate);

public class AndNotSpecification : CompositeSpecification

private ISpecification _leftCondition;
private ISpecification _rightCondition;

public AndNotSpecification(ISpecification left, ISpecification right)

_leftCondition = left;
_rightCondition = right;

public override bool IsSatisfiedBy(object candidate)

return _leftCondition.IsSatisfiedBy(candidate) && _rightCondition.IsSatisfiedBy(candidate) != true;

public class OrSpecification : CompositeSpecification

private ISpecification _leftCondition;
private ISpecification _rightCondition;

public OrSpecification(ISpecification left, ISpecification right)

_leftCondition = left;
_rightCondition = right;

public override bool IsSatisfiedBy(object candidate)

return _leftCondition.IsSatisfiedBy(candidate) || _rightCondition.IsSatisfiedBy(candidate);

public class OrNotSpecification : CompositeSpecification

private ISpecification _leftCondition;
private ISpecification _rightCondition;

public OrNotSpecification(ISpecification left, ISpecification right)

_leftCondition = left;
_rightCondition = right;

public override bool IsSatisfiedBy(object candidate)

return _leftCondition.IsSatisfiedBy(candidate) || _rightCondition.IsSatisfiedBy(candidate) != true;

public class NotSpecification : CompositeSpecification

private ISpecification _wrapped;

public NotSpecification(ISpecification x)

_wrapped = x;

public override bool IsSatisfiedBy(object candidate)

return !_wrapped.IsSatisfiedBy(candidate);

### C# 6.0 with generics

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 abstract class LinqSpecification<T> : CompositeSpecification<T>

public abstract Expression<Func<T, bool>> AsExpression();
public override bool IsSatisfiedBy(T candidate) => AsExpression().Compile()(candidate);

public abstract class CompositeSpecification<T> : ISpecification<T>

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 class AndSpecification<T> : CompositeSpecification<T>

private ISpecification<T> _left;
private ISpecification<T> _right;

public AndSpecification(ISpecification<T> left, ISpecification<T> right)

_left = left;
_right = right;

public override bool IsSatisfiedBy(T candidate) => _left.IsSatisfiedBy(candidate) && _right.IsSatisfiedBy(candidate);

public class AndNotSpecification<T> : CompositeSpecification<T>

private ISpecification<T> _left;
private ISpecification<T> _right;

public AndNotSpecification(ISpecification<T> left, ISpecification<T> right)

_left = left;
_right = right;

public override bool IsSatisfiedBy(T candidate) => _left.IsSatisfiedBy(candidate) && !_right.IsSatisfiedBy(candidate);

public class OrSpecification<T> : CompositeSpecification<T>

private ISpecification<T> _left;
private ISpecification<T> _right;

public OrSpecification(ISpecification<T> left, ISpecification<T> right)

_left = left;
_right = right;

public override bool IsSatisfiedBy(T candidate) => _left.IsSatisfiedBy(candidate) || _right.IsSatisfiedBy(candidate);

public class OrNotSpecification<T> : CompositeSpecification<T>

private ISpecification<T> _left;
private ISpecification<T> _right;

public OrNotSpecification(ISpecification<T> left, ISpecification<T> right)

_left = left;
_right = right;

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

### Python

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any

class BaseSpecification(ABC):
@abstractmethod
def is_satisfied_by(self, candidate: Any) -> bool:
raise NotImplementedError()

def __call__(self, candidate: Any) -> bool:
return self.is_satisfied_by(candidate)

def __and__(self, other: "BaseSpecification") -> "AndSpecification":
return AndSpecification(self, other)

def __or__(self, other: "BaseSpecification") -> "OrSpecification":
return OrSpecification(self, other)

def __neg__(self) -> "NotSpecification":
return NotSpecification(self)

@dataclass(frozen=True)
class AndSpecification(BaseSpecification):
first: BaseSpecification
second: BaseSpecification

def is_satisfied_by(self, candidate: Any) -> bool:
return self.first.is_satisfied_by(candidate) and self.second.is_satisfied_by(candidate)

@dataclass(frozen=True)
class OrSpecification(BaseSpecification):
first: BaseSpecification
second: BaseSpecification

def is_satisfied_by(self, candidate: Any) -> bool:
return self.first.is_satisfied_by(candidate) or self.second.is_satisfied_by(candidate)

@dataclass(frozen=True)
class NotSpecification(BaseSpecification):
subject: BaseSpecification

def is_satisfied_by(self, candidate: Any) -> bool:
return not self.subject.is_satisfied_by(candidate)

### C++

template <class T>
class ISpecification

public:
virtual ~ISpecification() = default;
virtual bool IsSatisfiedBy(T Candidate) const = 0;
virtual ISpecification<T>* And(const ISpecification<T>& Other) const = 0;
virtual ISpecification<T>* AndNot(const ISpecification<T>& Other) const = 0;
virtual ISpecification<T>* Or(const ISpecification<T>& Other) const = 0;
virtual ISpecification<T>* OrNot(const ISpecification<T>& Other) const = 0;
virtual ISpecification<T>* Not() const = 0;

template <class T>
class CompositeSpecification : public ISpecification<T>

public:
virtual bool IsSatisfiedBy(T Candidate) const override = 0;

virtual ISpecification<T>* And(const ISpecification<T>& Other) const override;
virtual ISpecification<T>* AndNot(const ISpecification<T>& Other) const override;
virtual ISpecification<T>* Or(const ISpecification<T>& Other) const override;
virtual ISpecification<T>* OrNot(const ISpecification<T>& Other) const override;
virtual ISpecification<T>* Not() const override;

template <class T>
class AndSpecification final : public CompositeSpecification<T>

public:
const ISpecification<T>& Left;
const ISpecification<T>& Right;

AndSpecification(const ISpecification<T>& InLeft, const ISpecification<T>& InRight)
: Left(InLeft),
Right(InRight) { }

virtual bool IsSatisfiedBy(T Candidate) const override

return Left.IsSatisfiedBy(Candidate) && Right.IsSatisfiedBy(Candidate);

template <class T>
ISpecification<T>* CompositeSpecification<T>::And(const ISpecification<T>& Other) const

return new AndSpecification<T>(*this, Other);

template <class T>
class AndNotSpecification final : public CompositeSpecification<T>

public:
const ISpecification<T>& Left;
const ISpecification<T>& Right;

AndNotSpecification(const ISpecification<T>& InLeft, const ISpecification<T>& InRight)
: Left(InLeft),
Right(InRight) { }

virtual bool IsSatisfiedBy(T Candidate) const override

return Left.IsSatisfiedBy(Candidate) && !Right.IsSatisfiedBy(Candidate);

template <class T>
class OrSpecification final : public CompositeSpecification<T>

public:
const ISpecification<T>& Left;
const ISpecification<T>& Right;

OrSpecification(const ISpecification<T>& InLeft, const ISpecification<T>& InRight)
: Left(InLeft),
Right(InRight) { }

virtual bool IsSatisfiedBy(T Candidate) const override

return Left.IsSatisfiedBy(Candidate) || Right.IsSatisfiedBy(Candidate);

template <class T>
class OrNotSpecification final : public CompositeSpecification<T>

public:
const ISpecification<T>& Left;
const ISpecification<T>& Right;

OrNotSpecification(const ISpecification<T>& InLeft, const ISpecification<T>& InRight)
: Left(InLeft),
Right(InRight) { }

virtual bool IsSatisfiedBy(T Candidate) const override

return Left.IsSatisfiedBy(Candidate) || !Right.IsSatisfiedBy(Candidate);

template <class T>
class NotSpecification final : public CompositeSpecification<T>

public:
const ISpecification<T>& Other;

NotSpecification(const ISpecification<T>& InOther)
: Other(InOther) { }

virtual bool IsSatisfiedBy(T Candidate) const override

return !Other.IsSatisfiedBy(Candidate);

template <class T>
ISpecification<T>* CompositeSpecification<T>::AndNot(const ISpecification<T>& Other) const

return new AndNotSpecification<T>(*this, Other);

template <class T>
ISpecification<T>* CompositeSpecification<T>::Or(const ISpecification<T>& Other) const

return new OrSpecification<T>(*this, Other);

template <class T>
ISpecification<T>* CompositeSpecification<T>::OrNot(const ISpecification<T>& Other) const

return new OrNotSpecification<T>(*this, Other);

template <class T>
ISpecification<T>* CompositeSpecification<T>::Not() const

return new NotSpecification<T>(*this);

### TypeScript

export interface ISpecification {
isSatisfiedBy(candidate: unknown): boolean;
and(other: ISpecification): ISpecification;
andNot(other: ISpecification): ISpecification;
or(other: ISpecification): ISpecification;
orNot(other: ISpecification): ISpecification;
not(): ISpecification;

export abstract class CompositeSpecification implements ISpecification {
abstract isSatisfiedBy(candidate: unknown): boolean;

and(other: ISpecification): ISpecification {
return new AndSpecification(this, other);

andNot(other: ISpecification): ISpecification {
return new AndNotSpecification(this, other);

or(other: ISpecification): ISpecification {
return new OrSpecification(this, other);

orNot(other: ISpecification): ISpecification {
return new OrNotSpecification(this, other);

not(): ISpecification {
return new NotSpecification(this);

export class AndSpecification extends CompositeSpecification {
constructor(private leftCondition: ISpecification, private rightCondition: ISpecification) {
super();

isSatisfiedBy(candidate: unknown): boolean {
return this.leftCondition.isSatisfiedBy(candidate) && this.rightCondition.isSatisfiedBy(candidate);

export class AndNotSpecification extends CompositeSpecification {
constructor(private leftCondition: ISpecification, private rightCondition: ISpecification) {
super();

isSatisfiedBy(candidate: unknown): boolean {
return this.leftCondition.isSatisfiedBy(candidate) && this.rightCondition.isSatisfiedBy(candidate) !== true;

export class OrSpecification extends CompositeSpecification {
constructor(private leftCondition: ISpecification, private rightCondition: ISpecification) {
super();

isSatisfiedBy(candidate: unknown): boolean {
return this.leftCondition.isSatisfiedBy(candidate) || this.rightCondition.isSatisfiedBy(candidate);

export class OrNotSpecification extends CompositeSpecification {
constructor(private leftCondition: ISpecification, private rightCondition: ISpecification) {
super();

isSatisfiedBy(candidate: unknown): boolean {
return this.leftCondition.isSatisfiedBy(candidate) || this.rightCondition.isSatisfiedBy(candidate) !== true;

export class NotSpecification extends CompositeSpecification {
constructor(private wrapped: ISpecification) {
super();

isSatisfiedBy(candidate: unknown): boolean {
return !this.wrapped.isSatisfiedBy(candidate);

## Example of use

In the next example, invoices are retrieved and sent to a collection agency if:

1. they are overdue,
2. notices have been sent, and
3. they are not already with the collection agency.

This example is meant to show the result of how the logic is 'chained' together.

This usage example assumes a previously defined `OverdueSpecification` class that 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. The implementation of these classes isn't important here.

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.

var overdue = new OverdueSpecification();
var noticeSent = new NoticeSentSpecification();
var inCollection = new InCollectionSpecification();

// Example of specification pattern logic chaining
var sendToCollection = overdue.And(noticeSent).And(inCollection.Not());

var invoices = InvoiceService.GetInvoices();

foreach (var invoice in invoices)

if (sendToCollection.IsSatisfiedBy(invoice))

invoice.SendToCollection();

## References

* Evans, Eric (2004). Domain Driven Design. Addison-Wesley. p. 224.

## External links

* Specifications by Eric Evans and Martin Fowler
* The Specification Pattern: A Primer by Matt Berther
* The Specification Pattern: A Four Part Introduction using VB.Net  by Richard Dalton
* The Specification Pattern in PHP by Moshe Brevda
* Happyr Doctrine Specification in PHP by Happyr
* The Specification Pattern in Swift by Simon Strandgaard
* The Specification Pattern in TypeScript and JavaScript by Thiago Delgado Pinto
* specification pattern in flash actionscript 3 by Rolf Vreijdenberger

Template:Design patterns

0.00

(0 votes)

Original source: https://en.wikipedia.org/wiki/Specification pattern. Read more

|

Retrieved from "https://handwiki.org/wiki/index.php?title=Specification_pattern&oldid=4157276"