Specificație (model de design)

O „specificație” în programare este un model de proiectare prin care o reprezentare a regulilor logicii de afaceri poate fi transformată într-un lanț de obiecte legate prin operații logice booleene .

Acest model evidențiază acele specificații (reguli) din logica de afaceri care sunt potrivite pentru „cuplarea” cu altele. Obiectul logic de afaceri își moștenește funcționalitatea din clasa abstractă de agregare CompositeSpecification, care conține o singură metodă IsSatisfiedBy care returnează o valoare booleană. Odată instanțiat, un obiect este legat cu alte obiecte. Drept urmare, fără a pierde flexibilitatea în personalizarea logicii de afaceri, putem adăuga cu ușurință noi reguli.

Exemple de cod

C#

interfață publică ISpecification { bool IsSatisfiedBy ( obiect candidat ); ISspecificația Și ( ISspecificația altele ); ISspecificație Sau ( ISspecificație altele ); ISspecificationNot ( ); } public abstract class CompositeSpecification : ISpecification { public abstract bool IsSatisfiedBy ( candidat obiect ); public ISpecification Și ( ISpecification other ) { return new AndSpecification ( this , other ); } public ISpecification Or ( ISpecification other ) { return new OrSpecification ( aceasta , altele ); } public ISpecification Not () { return new NotSpecification ( this ); } } public class AndSpecification : CompositeSpecification { private ISpecification One ; private ISspecificație Altele ; public AndSpecification ( ISspecificaţia x , ISspecificaţia y ) { One = x ; Altele = y _ } public override bool IsSatisfiedBy ( candidat obiect ) { return One . IsSatisfiedBy ( candidat ) && Altele . IsSatisfiedBy ( candidat ); } } public class OrSpecification : CompositeSpecification { private ISpecification One ; private ISspecificație Altele ; public OrSpecification ( ISspecificaţia x , ISspecificaţia y ) { One = x ; Altele = y _ } public override bool IsSatisfiedBy ( candidat obiect ) { return One . IsSatisfiedBy ( candidat ) || Altele . IsSatisfiedBy ( candidat ); } } public class NotSpecification : CompositeSpecification { private ISpecification Wrapped ; public NotSpecification ( ISpecification x ) { Wrapped = x ; } public override bool IsSatisfiedBy ( candidat obiect ) { return ! înfășurat . IsSatisfiedBy ( candidat ); } }

C# 3.0 , simplificat prin șabloane și metode de extensie

interfață publică ISpecification < TEntity > { bool IsSatisfiedBy ( TEntity entity ); } clasa internă AndSpecification < TEntity > : ISpecification < TEntity > { private readonly ISpecification < TEntity > _spec1 ; private readonly ISpecification < TEntity > _spec2 ; protected ISpecification < TEntity > Spec1 { get { return _spec1 ; } } protected ISpecification < TEntity > Spec2 { get { return _spec2 ; } } intern AndSpecification ( ISpecification < TEntity > spec1 , ISpecification < TEntity > spec2 ) { if ( spec1 == null ) throw new ArgumentNullException ( "spec1" ); if ( spec2 == null ) aruncă o nouă excepție ArgumentNullException ( "spec2" ); _spec1 = spec1 ; _spec2 = spec2 ; } public bool IsSatisfiedBy ( TEntity candidat ) { return Spec1 . IsSatisfiedBy ( candidat ) && Spec2 . IsSatisfiedBy ( candidat ); } } clasa internă OrSpecification < TEntity > : ISpecification < TEntity > { private readonly ISpecification < TEntity > _spec1 ; private readonly ISpecification < TEntity > _spec2 ; protected ISpecification < TEntity > Spec1 { get { return _spec1 ; } } protected ISpecification < TEntity > Spec2 { get { return _spec2 ; } } internal OrSpecification ( ISpecification < TEntity > spec1 , ISpecification < TEntity > spec2 ) { if ( spec1 == null ) throw new ArgumentNullException ( "spec1" ); if ( spec2 == null ) aruncă o nouă excepție ArgumentNullException ( "spec2" ); _spec1 = spec1 ; _spec2 = spec2 ; } public bool IsSatisfiedBy ( TEntity candidat ) { return Spec1 . IsSatisfiedBy ( candidat ) || spec2 . IsSatisfiedBy ( candidat ); } } clasa internă NotSpecification < TEntity > : ISpecification < TEntity > { private readonly ISpecification < TEntity > _wrapped ; protejat Ispecificație < TEntity > Wrapped { get { return _wrapped ; } } intern NotSpecification ( ISpecification < TEntity > spec ) { if ( spec == null ) { throw new ArgumentNullException ( "spec" ); } _wrapped = spec ; } public bool IsSatisfiedBy ( TEntity candidat ) { return ! înfășurat . IsSatisfiedBy ( candidat ); } } public static class ExtensionMethods { public static ISpecification < TEntity > And < TEntity >( această ISpecification < TEntity > spec1 , ISpecification < TEntity > spec2 ) { return new AndSpecification < TEntity >( spec1 , spec2 ); } public static ISpecification < TEntity > Sau < TEntity >( acest ISpecification < TEntity > spec1 , ISpecification < TEntity > spec2 ) { return new OrSpecification < TEntity >( spec1 , spec2 ); } public static ISpecification < TEntity > Not < TEntity >( this ISpecification < TEntity > spec ) { return new NotSpecification < TEntity >( spec ); } }

Exemplu de utilizare

În exemplul următor, verificăm facturile și le trimitem unei agenții de colectare dacă: sunt restante, nu au fost încă trimise la agenția de colectare și i s-a trimis un avertisment cumpărătorului. Acest exemplu arată cum regulile sunt „înlănțuite” una de cealaltă.

Exemplul se bazează pe trei specificații: OverdueSpecification, care este adevărată dacă factura a fost emisă cu mai mult de 30 de zile în urmă, NoticeSentSpecification, care este adevărată dacă au fost trimise 3 avertismente către client și InCollectionSpecification, care verifică dacă factura nu a fost încă trimisă. către agenția de colectare. Implementarea acestor clase nu este atât de importantă.

Folosind aceste trei specificații, creăm o nouă regulă SendToCollection care este adevărată dacă toate cele trei condiții descrise în paragraful anterior sunt adevărate.

OverDueSpecification OverDue = nou OverDueSpecification (); NoticeSentSpecification NoticeSent = nou NoticeSentSpecification (); InCollectionSpecification InCollection = nou InCollectionSpecification (); // exemplu de reguli de înlănțuire ISpecification < Invoice > SendToCollection = OverDue . Și ( NoticeSent ). Și ( ÎnColecție . Nu ()); InvoiceCollection = Service . GetInvoices (); foreach ( Invoice currentInvoice in InvoiceCollection ) { if ( SendToCollection . IsSatisfiedBy ( currentInvoice )) { currentInvoice . SendToCollection (); } }

Note

Literatură

  • Evans, E: „Domain-Driven Design”, pagina 224. Addison-Wesley, 2004.

Link -uri