Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Specification pattern

From Wikipedia, the free encyclopedia
Software design pattern
Specification Pattern inUML

In computer programming, thespecification pattern is a particularsoftware design pattern, wherebybusiness rules can be recombined by chaining the business rules together usingBoolean logic. The pattern is frequently used in the context ofdomain-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 orinversion 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.

Code examples

[edit]

C#

[edit]
Further information:C Sharp (programming language)
publicinterfaceISpecification{boolIsSatisfiedBy(objectcandidate);ISpecificationAnd(ISpecificationother);ISpecificationAndNot(ISpecificationother);ISpecificationOr(ISpecificationother);ISpecificationOrNot(ISpecificationother);ISpecificationNot();}publicabstractclassCompositeSpecification:ISpecification{publicabstractboolIsSatisfiedBy(objectcandidate);publicISpecificationAnd(ISpecificationother){returnnewAndSpecification(this,other);}publicISpecificationAndNot(ISpecificationother){returnnewAndNotSpecification(this,other);}publicISpecificationOr(ISpecificationother){returnnewOrSpecification(this,other);}publicISpecificationOrNot(ISpecificationother){returnnewOrNotSpecification(this,other);}publicISpecificationNot(){returnnewNotSpecification(this);}}publicclassAndSpecification:CompositeSpecification{privateISpecification_leftCondition;privateISpecification_rightCondition;publicAndSpecification(ISpecificationleft,ISpecificationright){_leftCondition=left;_rightCondition=right;}publicoverrideboolIsSatisfiedBy(objectcandidate){return_leftCondition.IsSatisfiedBy(candidate)&&_rightCondition.IsSatisfiedBy(candidate);}}publicclassAndNotSpecification:CompositeSpecification{privateISpecification_leftCondition;privateISpecification_rightCondition;publicAndNotSpecification(ISpecificationleft,ISpecificationright){_leftCondition=left;_rightCondition=right;}publicoverrideboolIsSatisfiedBy(objectcandidate){return_leftCondition.IsSatisfiedBy(candidate)&&_rightCondition.IsSatisfiedBy(candidate)!=true;}}publicclassOrSpecification:CompositeSpecification{privateISpecification_leftCondition;privateISpecification_rightCondition;publicOrSpecification(ISpecificationleft,ISpecificationright){_leftCondition=left;_rightCondition=right;}publicoverrideboolIsSatisfiedBy(objectcandidate){return_leftCondition.IsSatisfiedBy(candidate)||_rightCondition.IsSatisfiedBy(candidate);}}publicclassOrNotSpecification:CompositeSpecification{privateISpecification_leftCondition;privateISpecification_rightCondition;publicOrNotSpecification(ISpecificationleft,ISpecificationright){_leftCondition=left;_rightCondition=right;}publicoverrideboolIsSatisfiedBy(objectcandidate){return_leftCondition.IsSatisfiedBy(candidate)||_rightCondition.IsSatisfiedBy(candidate)!=true;}}publicclassNotSpecification:CompositeSpecification{privateISpecification_wrapped;publicNotSpecification(ISpecificationx){_wrapped=x;}publicoverrideboolIsSatisfiedBy(objectcandidate){return!_wrapped.IsSatisfiedBy(candidate);}}

C# 6.0 with generics

[edit]
Further information:C Sharp (programming language)
publicinterfaceISpecification<T>{boolIsSatisfiedBy(Tcandidate);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();}publicabstractclassLinqSpecification<T>:CompositeSpecification<T>{publicabstractExpression<Func<T,bool>>AsExpression();publicoverrideboolIsSatisfiedBy(Tcandidate)=>AsExpression().Compile()(candidate);}publicabstractclassCompositeSpecification<T>:ISpecification<T>{publicabstractboolIsSatisfiedBy(Tcandidate);publicISpecification<T>And(ISpecification<T>other)=>newAndSpecification<T>(this,other);publicISpecification<T>AndNot(ISpecification<T>other)=>newAndNotSpecification<T>(this,other);publicISpecification<T>Or(ISpecification<T>other)=>newOrSpecification<T>(this,other);publicISpecification<T>OrNot(ISpecification<T>other)=>newOrNotSpecification<T>(this,other);publicISpecification<T>Not()=>newNotSpecification<T>(this);}publicclassAndSpecification<T>:CompositeSpecification<T>{privateISpecification<T>_left;privateISpecification<T>_right;publicAndSpecification(ISpecification<T>left,ISpecification<T>right){_left=left;_right=right;}publicoverrideboolIsSatisfiedBy(Tcandidate)=>_left.IsSatisfiedBy(candidate)&&_right.IsSatisfiedBy(candidate);}publicclassAndNotSpecification<T>:CompositeSpecification<T>{privateISpecification<T>_left;privateISpecification<T>_right;publicAndNotSpecification(ISpecification<T>left,ISpecification<T>right){_left=left;_right=right;}publicoverrideboolIsSatisfiedBy(Tcandidate)=>_left.IsSatisfiedBy(candidate)&&!_right.IsSatisfiedBy(candidate);}publicclassOrSpecification<T>:CompositeSpecification<T>{privateISpecification<T>_left;privateISpecification<T>_right;publicOrSpecification(ISpecification<T>left,ISpecification<T>right){_left=left;_right=right;}publicoverrideboolIsSatisfiedBy(Tcandidate)=>_left.IsSatisfiedBy(candidate)||_right.IsSatisfiedBy(candidate);}publicclassOrNotSpecification<T>:CompositeSpecification<T>{privateISpecification<T>_left;privateISpecification<T>_right;publicOrNotSpecification(ISpecification<T>left,ISpecification<T>right){_left=left;_right=right;}publicoverrideboolIsSatisfiedBy(Tcandidate)=>_left.IsSatisfiedBy(candidate)||!_right.IsSatisfiedBy(candidate);}publicclassNotSpecification<T>:CompositeSpecification<T>{ISpecification<T>other;publicNotSpecification(ISpecification<T>other)=>this.other=other;publicoverrideboolIsSatisfiedBy(Tcandidate)=>!other.IsSatisfiedBy(candidate);}

Python

[edit]
Further information:Python (programming language)
fromabcimportABC,abstractmethodfromdataclassesimportdataclassfromtypingimportAnyclassBaseSpecification(ABC):@abstractmethoddefis_satisfied_by(self,candidate:Any)->bool:raiseNotImplementedError()def__call__(self,candidate:Any)->bool:returnself.is_satisfied_by(candidate)def__and__(self,other:"BaseSpecification")->"AndSpecification":returnAndSpecification(self,other)def__or__(self,other:"BaseSpecification")->"OrSpecification":returnOrSpecification(self,other)def__neg__(self)->"NotSpecification":returnNotSpecification(self)@dataclass(frozen=True)classAndSpecification(BaseSpecification):first:BaseSpecificationsecond:BaseSpecificationdefis_satisfied_by(self,candidate:Any)->bool:returnself.first.is_satisfied_by(candidate)andself.second.is_satisfied_by(candidate)@dataclass(frozen=True)classOrSpecification(BaseSpecification):first:BaseSpecificationsecond:BaseSpecificationdefis_satisfied_by(self,candidate:Any)->bool:returnself.first.is_satisfied_by(candidate)orself.second.is_satisfied_by(candidate)@dataclass(frozen=True)classNotSpecification(BaseSpecification):subject:BaseSpecificationdefis_satisfied_by(self,candidate:Any)->bool:returnnotself.subject.is_satisfied_by(candidate)

C++

[edit]
Further information:C++
template<classT>classISpecification{public:virtual~ISpecification()=default;virtualboolIsSatisfiedBy(TCandidate)const=0;virtualISpecification<T>*And(constISpecification<T>&Other)const=0;virtualISpecification<T>*AndNot(constISpecification<T>&Other)const=0;virtualISpecification<T>*Or(constISpecification<T>&Other)const=0;virtualISpecification<T>*OrNot(constISpecification<T>&Other)const=0;virtualISpecification<T>*Not()const=0;};template<classT>classCompositeSpecification:publicISpecification<T>{public:virtualboolIsSatisfiedBy(TCandidate)constoverride=0;virtualISpecification<T>*And(constISpecification<T>&Other)constoverride;virtualISpecification<T>*AndNot(constISpecification<T>&Other)constoverride;virtualISpecification<T>*Or(constISpecification<T>&Other)constoverride;virtualISpecification<T>*OrNot(constISpecification<T>&Other)constoverride;virtualISpecification<T>*Not()constoverride;};template<classT>classAndSpecificationfinal:publicCompositeSpecification<T>{public:constISpecification<T>&Left;constISpecification<T>&Right;AndSpecification(constISpecification<T>&InLeft,constISpecification<T>&InRight):Left(InLeft),Right(InRight){}virtualboolIsSatisfiedBy(TCandidate)constoverride{returnLeft.IsSatisfiedBy(Candidate)&&Right.IsSatisfiedBy(Candidate);}};template<classT>ISpecification<T>*CompositeSpecification<T>::And(constISpecification<T>&Other)const{returnnewAndSpecification<T>(*this,Other);}template<classT>classAndNotSpecificationfinal:publicCompositeSpecification<T>{public:constISpecification<T>&Left;constISpecification<T>&Right;AndNotSpecification(constISpecification<T>&InLeft,constISpecification<T>&InRight):Left(InLeft),Right(InRight){}virtualboolIsSatisfiedBy(TCandidate)constoverride{returnLeft.IsSatisfiedBy(Candidate)&&!Right.IsSatisfiedBy(Candidate);}};template<classT>classOrSpecificationfinal:publicCompositeSpecification<T>{public:constISpecification<T>&Left;constISpecification<T>&Right;OrSpecification(constISpecification<T>&InLeft,constISpecification<T>&InRight):Left(InLeft),Right(InRight){}virtualboolIsSatisfiedBy(TCandidate)constoverride{returnLeft.IsSatisfiedBy(Candidate)||Right.IsSatisfiedBy(Candidate);}};template<classT>classOrNotSpecificationfinal:publicCompositeSpecification<T>{public:constISpecification<T>&Left;constISpecification<T>&Right;OrNotSpecification(constISpecification<T>&InLeft,constISpecification<T>&InRight):Left(InLeft),Right(InRight){}virtualboolIsSatisfiedBy(TCandidate)constoverride{returnLeft.IsSatisfiedBy(Candidate)||!Right.IsSatisfiedBy(Candidate);}};template<classT>classNotSpecificationfinal:publicCompositeSpecification<T>{public:constISpecification<T>&Other;NotSpecification(constISpecification<T>&InOther):Other(InOther){}virtualboolIsSatisfiedBy(TCandidate)constoverride{return!Other.IsSatisfiedBy(Candidate);}};template<classT>ISpecification<T>*CompositeSpecification<T>::AndNot(constISpecification<T>&Other)const{returnnewAndNotSpecification<T>(*this,Other);}template<classT>ISpecification<T>*CompositeSpecification<T>::Or(constISpecification<T>&Other)const{returnnewOrSpecification<T>(*this,Other);}template<classT>ISpecification<T>*CompositeSpecification<T>::OrNot(constISpecification<T>&Other)const{returnnewOrNotSpecification<T>(*this,Other);}template<classT>ISpecification<T>*CompositeSpecification<T>::Not()const{returnnewNotSpecification<T>(*this);}

TypeScript

[edit]
Further information:TypeScript
exportinterfaceISpecification{isSatisfiedBy(candidate:unknown):boolean;and(other:ISpecification):ISpecification;andNot(other:ISpecification):ISpecification;or(other:ISpecification):ISpecification;orNot(other:ISpecification):ISpecification;not():ISpecification;}exportabstractclassCompositeSpecificationimplementsISpecification{abstractisSatisfiedBy(candidate:unknown):boolean;and(other:ISpecification):ISpecification{returnnewAndSpecification(this,other);}andNot(other:ISpecification):ISpecification{returnnewAndNotSpecification(this,other);}or(other:ISpecification):ISpecification{returnnewOrSpecification(this,other);}orNot(other:ISpecification):ISpecification{returnnewOrNotSpecification(this,other);}not():ISpecification{returnnewNotSpecification(this);}}exportclassAndSpecificationextendsCompositeSpecification{constructor(privateleftCondition:ISpecification,privaterightCondition:ISpecification){super();}isSatisfiedBy(candidate:unknown):boolean{returnthis.leftCondition.isSatisfiedBy(candidate)&&this.rightCondition.isSatisfiedBy(candidate);}}exportclassAndNotSpecificationextendsCompositeSpecification{constructor(privateleftCondition:ISpecification,privaterightCondition:ISpecification){super();}isSatisfiedBy(candidate:unknown):boolean{returnthis.leftCondition.isSatisfiedBy(candidate)&&this.rightCondition.isSatisfiedBy(candidate)!==true;}}exportclassOrSpecificationextendsCompositeSpecification{constructor(privateleftCondition:ISpecification,privaterightCondition:ISpecification){super();}isSatisfiedBy(candidate:unknown):boolean{returnthis.leftCondition.isSatisfiedBy(candidate)||this.rightCondition.isSatisfiedBy(candidate);}}exportclassOrNotSpecificationextendsCompositeSpecification{constructor(privateleftCondition:ISpecification,privaterightCondition:ISpecification){super();}isSatisfiedBy(candidate:unknown):boolean{returnthis.leftCondition.isSatisfiedBy(candidate)||this.rightCondition.isSatisfiedBy(candidate)!==true;}}exportclassNotSpecificationextendsCompositeSpecification{constructor(privatewrapped:ISpecification){super();}isSatisfiedBy(candidate:unknown):boolean{return!this.wrapped.isSatisfiedBy(candidate);}}

Example of use

[edit]

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 definedOverdueSpecification class that is satisfied when an invoice's due date is 30 days or older, aNoticeSentSpecification class that is satisfied when three notices have been sent to the customer, and anInCollectionSpecification 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 calledSendToCollection 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.

varoverdue=newOverdueSpecification();varnoticeSent=newNoticeSentSpecification();varinCollection=newInCollectionSpecification();// Example of specification pattern logic chainingvarsendToCollection=overdue.And(noticeSent).And(inCollection.Not());varinvoices=InvoiceService.GetInvoices();foreach(varinvoiceininvoices){if(sendToCollection.IsSatisfiedBy(invoice)){invoice.SendToCollection();}}

References

[edit]
  • Evans, Eric (2004).Domain Driven Design. Addison-Wesley. p. 224.

External links

[edit]
Gang of Four
patterns
Creational
Structural
Behavioral
Concurrency
patterns
Architectural
patterns
Other
patterns
Books
People
Communities
See also
Retrieved from "https://en.wikipedia.org/w/index.php?title=Specification_pattern&oldid=1312009825"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp