Specifikation (designmönster)

En "specifikation" i programmering är ett designmönster varigenom en representation av affärslogikregler kan omvandlas till en kedja av objekt sammanlänkade med booleska logiska operationer .

Detta mönster belyser de specifikationer (regler) inom affärslogik som är lämpliga att "koppla" med andra. Affärslogikobjektet ärver sin funktionalitet från den abstrakta aggregationsklassen CompositeSpecification, som endast innehåller en IsSatisfiedBy-metod som returnerar ett booleskt värde. När ett objekt har instansierats är det kedjat med andra objekt. Som ett resultat, utan att förlora flexibiliteten i att anpassa affärslogik, kan vi enkelt lägga till nya regler.

Kodexempel

C#

offentligt gränssnitt ISpecification { bool IsSatisfiedBy ( objektkandidat ) ; ISpecification And ( ISPecification annan ); ISpecification Eller ( ISPecification annan ); ISpecificationNot ( ); } public abstract class CompositeSpecification : ISpecification { public abstract bool IsSatisfiedBy ( objektkandidat ) ; public ISpecification And ( ISPecification other ) { return new AndSpecification ( this , other ); } public ISpecification Eller ( ISPecification other ) { return new OrSpecification ( this , other ); } public ISpecification Not () { return new NotSpecification ( this ); } } public class AndSpecification : CompositeSpecification { privat ISpecification One ; privat ISpecifikation Övrigt ; public AndSpecification ( ISPecification x , ISpecification y ) { One = x ; Annat = y _ } public override bool IsSatisfiedBy ( objektkandidat ) { return One . _ Är nöjd med ( kandidat ) && Övrigt . IsSatisfiedBy ( kandidat ); } } public class OrSpecification : CompositeSpecification { privat ISpecification One ; privat ISpecifikation Övrigt ; public OrSpecification ( ISPecification x , ISSpecification y ) { One = x ; Annat = y _ } public override bool IsSatisfiedBy ( objektkandidat ) { return One . _ IsSatisfiedBy ( kandidat ) || Annat . IsSatisfiedBy ( kandidat ); } } public class NotSpecification : CompositeSpecification { privat ISpecification Wrapped ; public NotSpecification ( ISPecification x ) { Wrapped = x ; } public override bool IsSatisfiedBy ( objektkandidat ) { return ! _ inslagna . IsSatisfiedBy ( kandidat ); } }

C# 3.0 , förenklad genom mallar och tilläggsmetoder

offentligt gränssnitt ISpecification < TENtity > { bool IsSatisfiedBy ( TENtity- enhet ); } intern klass AndSpecification < TENtity > : ISpecification < TENtity > { privat skrivskyddad ISpecification < TENtity > _spec1 ; privat skrivskyddad ISpecification < TENtity > _spec2 ; skyddad ISpecification < TENtity > Spec1 { get { return _spec1 ; } } skyddad ISpecification < TENtity > Spec2 { get { return _spec2 ; } } intern AndSpecification ( ISSpecification < TENtity > spec1 , ISSpecification < TENtity > spec2 ) { if ( spec1 == null ) throw new ArgumentNullException ( "spec1" ); if ( spec2 == null ) kasta nytt ArgumentNullException ( "spec2" ); _spec1 = spec1 ; _spec2 = spec2 ; } public bool IsSatisfiedBy ( TENtity- kandidat ) { return Spec1 . IsSatisfiedBy ( kandidat ) && Spec2 . IsSatisfiedBy ( kandidat ); } } intern klass OrSpecification < TENtity > : ISpecification < TENtity > { privat skrivskyddad ISpecification < TENtity > _spec1 ; privat skrivskyddad ISpecification < TENtity > _spec2 ; skyddad ISpecification < TENtity > Spec1 { get { return _spec1 ; } } skyddad ISpecification < TENtity > Spec2 { get { return _spec2 ; } } intern OrSpecification ( ISSpecification < TENtity > spec1 , ISSpecification < TENtity > spec2 ) { if ( spec1 == null ) throw new ArgumentNullException ( "spec1" ); if ( spec2 == null ) kasta nytt ArgumentNullException ( "spec2" ); _spec1 = spec1 ; _spec2 = spec2 ; } public bool IsSatisfiedBy ( TENtity- kandidat ) { return Spec1 . IsSatisfiedBy ( kandidat ) || spec2 . IsSatisfiedBy ( kandidat ); } } intern klass NotSpecification < TENtity > : ISpecification < TENtity > { privat skrivskyddad ISpecification < TENtity > _wrapped ; protected ISpecification < TENtity > Wrapped { get { return _wrapped ; } } intern NotSpecification ( ISSpecification < TENtity > spec ) { if ( spec == null ) { throw new ArgumentNullException ( "spec" ); } _wrapped = spec ; } public bool IsSatisfiedBy ( TENtity- kandidat ) { return ! inslagna . IsSatisfiedBy ( kandidat ); } } public static class ExtensionMethods { public static ISpecification < TENtity > And < TENtity >( this ISpecification < TENtity > spec1 , ISSpecification < TENtity > spec2 ) { return new AndSpecification < TENtity >( spec1 , spec2 ); } public static ISpecification < TENtity > Eller < TENtity >( denna ISpecification < TENtity > spec1 , ISpecification < TENtity > spec2 ) { return new OrSpecification < TENtity >( spec1 , spec2 ); } public static ISpecification < TENtity > Not < TENtity >( denna ISpecification < TENtity > spec ) { return new NotSpecification < TENtity >( spec ); } }

Användningsexempel

I följande exempel kontrollerar vi fakturor och skickar dem till en inkassobyrå om: de är försenade, de ännu inte har skickats till inkassoföretaget och en varning har skickats till köparen. Detta exempel visar hur reglerna är "kedjade" till varandra.

Exemplet bygger på tre specifikationer: OverdueSpecification, vilket är sant om fakturan utfärdades för mer än 30 dagar sedan, NoticeSentSpecification, vilket är sant om 3 varningar skickades till kunden, och InCollectionSpecification, som kontrollerar att fakturan ännu inte har skickats till inkassobyrån. Genomförandet av dessa klasser är inte så viktigt.

Med hjälp av dessa tre specifikationer skapar vi en ny SendToCollection-regel som är sann om alla tre villkoren som beskrivs i föregående stycke är uppfyllda.

OverDueSpecification OverDue = ny OverDueSpecification (); NoticeSentSpecification NoticeSent = ny NoticeSentSpecification (); InCollectionSpecification InCollection = ny InCollectionSpecification (); // exempel på kedjeregler ISpecifikation < Faktura > SendToCollection = Förfallen . Och ( NoticeSent ). Och ( InCollection . Inte ()); InvoiceCollection = Tjänst . GetInvoices (); foreach ( Invoice currentInvoice in InvoiceCollection ) { if ( SendToCollection . IsSatisfiedBy ( currentInvoice )) { currentInvoice . SendToCollection (); } }

Anteckningar

Litteratur

  • Evans, E: "Domändriven design.", sid 224. Addison-Wesley, 2004.

Länkar