Patrón de especificación

Patrón de diseño de software
Patrón de especificación en UML

En programación informática, el patrón de especificación es un patrón de diseño de software particular , mediante el cual las reglas de negocio se pueden recombinar encadenándolas entre sí mediante lógica booleana . El patrón se utiliza con frecuencia en el contexto del diseño orientado al dominio .

Un patrón de especificación describe una regla de negocio que se puede combinar con otras reglas de negocio. En este patrón, una unidad de lógica de negocio hereda su funcionalidad de la clase de especificación compuesta agregada abstracta. La clase de especificación compuesta tiene una función llamada IsSatisfiedBy que devuelve un valor booleano. Después de la instanciación, la especificación se "encadena" con otras especificaciones, lo que hace que las nuevas especificaciones sean fáciles de mantener, pero que la lógica de negocio sea altamente personalizable. Además, tras la instanciación, la lógica de negocio puede, a través de la invocación de un método o la inversión de control , tener su estado alterado para convertirse en un delegado de otras clases, como un repositorio de persistencia.

Como consecuencia de la realización de la composición en tiempo de ejecución de la lógica empresarial/de dominio de alto nivel, el patrón de Especificación es una herramienta conveniente para convertir criterios de búsqueda de usuarios ad hoc en lógica de bajo nivel para que la procesen los repositorios.

Dado que una especificación es una encapsulación de lógica en una forma reutilizable, es muy simple realizar pruebas unitarias exhaustivas y, cuando se utiliza en este contexto, también es una implementación del patrón de objeto humilde.

Ejemplos de código

DO#

interfaz pública ISpecification { bool IsSatisfiedBy ( objeto candidato ); ISpecification And ( ISpecification otro ); ISpecification AndNot ( ISpecification otro ); ISpecification Or ( ISpecification otro ); ISpecification OrNot ( ISpecification otro ); ISpecification Not (); }                   clase abstracta pública CompositeSpecification : ISpecification { bool abstracto público IsSatisfiedBy ( objeto candidato );            public ISpecification And ( ISpecification otro ) { return new AndSpecification ( este , otro ); }           público ISpecification AndNot ( ISpecification otro ) { devolver nuevo AndNotSpecification ( este , otro ); }           public ISpecification Or ( ISpecification otro ) { return new OrSpecification ( este , otro ); }           público ISpecification OrNot ( ISpecification otro ) { devolver nuevo OrNotSpecification ( este , otro ); }           public ISpecification Not () { devolver nueva NotSpecification ( this ); } }        clase pública AndSpecification : CompositeSpecification { ISpecification privada condiciónIzquierda ; ISpecification privada condiciónDerecha ;            public AndSpecification ( ISpecification izquierda , ISpecification derecha ) { condiciónIzquierda = izquierda ; condiciónDerecha = derecha ; }              público anular bool IsSatisfiedBy ( objeto candidato ) { devolver leftCondition . IsSatisfiedBy ( candidato ) && rightCondition . IsSatisfiedBy ( candidato ); } }           clase pública AndNotSpecification : CompositeSpecification { ISpecification privada condiciónIzquierda ; ISpecification privada condiciónDerecha ;            public AndNotSpecification ( ISpecification izquierda , ISpecification derecha ) { condiciónIzquierda = izquierda ; condiciónDerecha = derecha ; }              público anular bool IsSatisfiedBy ( objeto candidato ) { devolver leftCondition . IsSatisfiedBy ( candidato ) && rightCondition . IsSatisfiedBy ( candidato ) != true ; } }             clase pública OrSpecification : CompositeSpecification { ISpecification privada condiciónIzquierda ; ISpecification privada condiciónDerecha ;           public OrSpecification ( ISpecification izquierda , ISpecification derecha ) { condiciónIzquierda = izquierda ; condiciónDerecha = derecha ; }              público anular bool IsSatisfiedBy ( objeto candidato ) { devolver leftCondition . IsSatisfiedBy ( candidato ) || rightCondition . IsSatisfiedBy ( candidato ); } }           clase pública OrNotSpecification : CompositeSpecification { ISpecification privada condiciónIzquierda ; ISpecification privada condiciónDerecha ;           público OrNotSpecification ( ISpecification izquierda , ISpecification derecha ) { condiciónIzquierda = izquierda ; condiciónDerecha = derecha ; }              público anular bool IsSatisfiedBy ( objeto candidato ) { devolver leftCondition . IsSatisfiedBy ( candidato ) || rightCondition . IsSatisfiedBy ( candidato ) != true ; } }             clase pública NotSpecification : CompositeSpecification { privada ISpecification Wrapped ;         público NotSpecification ( ISpecification x ) { Envuelto = x ; }         público anular bool IsSatisfiedBy ( objeto candidato ) { devolver ! Wrapped . IsSatisfiedBy ( candidato ); } }         

C# 6.0 con genéricos

interfaz pública ISpecification < T > { bool IsSatisfiedBy ( T candidato ); ISpecification < T > And ( ISpecification < T > otro ); ISpecification < T > AndNot ( ISpecification < T > otro ); ISpecification < T > Or ( ISpecification < T > otro ); ISpecification < T > OrNot ( ISpecification < T > otro ); ISpecification < T > Not (); }                   clase abstracta pública LinqSpecification < T > : CompositeSpecification < T > { expresión abstracta pública < Func < T , bool >> AsExpression (); bool público anulado IsSatisfiedBy ( T candidato ) => AsExpression (). Compile () ( candidato ); }                 clase abstracta pública CompositeSpecification < T > : ISpecification < T > { bool abstracto público IsSatisfiedBy ( T candidato ); ISpecification pública < T > And ( ISpecification < T > otro ) => nuevo AndSpecification < T > ( este , otro ); ISpecification pública < T > AndNot ( ISpecification < T > otro ) => nuevo AndNotSpecification < T > ( este , otro ); ISpecification pública < T > Or ( ISpecification < T > otro ) => nuevo OrSpecification < T > ( este , otro ); ISpecification pública < T > OrNot ( ISpecification < T > otro ) => nuevo OrNotSpecification < T > ( este , otro ); ISpecification pública < T > Not () => nuevo NotSpecification < T > ( este ); }                                                clase pública AndSpecification < T > : CompositeSpecification < T > { ISpecification < T > izquierda ; ISpecification < T > derecha ;         public AndSpecification ( ISpecification < T > izquierda , ISpecification < T > derecha ) { this . left = izquierda ; this . right = derecha ; }             público anular bool IsSatisfiedBy ( T candidato ) => izquierda . IsSatisfiedBy ( candidato ) && derecha . IsSatisfiedBy ( candidato ); }        clase pública AndNotSpecification < T > : CompositeSpecification < T > { ISpecification < T > izquierda ; ISpecification < T > derecha ;         public AndNotSpecification ( ISpecification < T > izquierda , ISpecification < T > derecha ) { este . izquierda = izquierda ; este . derecha = derecha ; }             público anular bool IsSatisfiedBy ( T candidato ) => izquierda . IsSatisfiedBy ( candidato ) && ! derecha . IsSatisfiedBy ( candidato ); }        clase pública OrSpecification < T > : CompositeSpecification < T > { ISpecification < T > izquierda ; ISpecification < T > derecha ;         public OrSpecification ( ISpecification < T > izquierda , ISpecification < T > derecha ) { this . left = izquierda ; this . right = derecha ; }             public override bool IsSatisfiedBy ( T candidato ) = > izquierda.IsSatisfiedBy ( candidato ) || derecha.IsSatisfiedBy ( candidato ) ; } public class OrNotSpecification <T> : CompositeSpecification <T> { ISpecification <T> izquierda ; ISpecification <T> derecha ;                 public OrNotSpecification ( ISpecification < T > izquierda , ISpecification < T > derecha ) { este . izquierda = izquierda ; este . derecha = derecha ; }             public override bool IsSatisfiedBy ( T candidato ) = > izquierda.IsSatisfiedBy ( candidato ) || ! derecha.IsSatisfiedBy ( candidato ) ; }        clase pública NotSpecification < T > : CompositeSpecification < T > { ISpecification < T > otro ; pública NotSpecification ( ISpecification < T > otro ) => este . otro = otro ; pública anulación bool IsSatisfiedBy ( T candidato ) => ! otro . IsSatisfiedBy ( candidato ); }                    

Pitón

desde  abc  import  ABC ,  método abstracto desde  clases de datos  importar  clase de datos desde  tipificación  importar  Cualquieraclase  BaseSpecification ( ABC ):  @abstractmethod  def  is_satisfied_by ( self ,  candidato :  Any )  ->  bool :  generar  NotImplementedError () def  __call__ ( self ,  candidato :  Cualquiera )  ->  bool :  return  self . is_satisfied_by ( candidato ) def  __and__ ( self ,  other :  "BaseSpecification" )  ->  "AndSpecification" :  return  AndSpecification ( self ,  other ) def  __or__ ( self ,  other :  "BaseSpecification" )  ->  "OrSpecification" :  return  OrSpecification ( self ,  other ) def  __neg__ ( self )  ->  "NoEspecificación" :  devuelve  NoEspecificación ( self )@dataclass ( frozen = True ) clase  AndSpecification ( BaseSpecification ):  primero :  BaseSpecification  segundo :  BaseSpecification def  is_satisfied_by ( self ,  candidato :  Cualquiera )  ->  bool :  devuelve  self . first . is_satisfied_by ( candidato )  y  self . second . is_satisfied_by ( candidato )@dataclass ( frozen = True ) clase  OrSpecification ( BaseSpecification ):  primero :  BaseSpecification  segundo :  BaseSpecification def  is_satisfied_by ( self ,  candidato :  Cualquiera )  ->  bool :  devuelve  self . first . is_satisfied_by ( candidato )  o  self . second . is_satisfied_by ( candidato )@dataclass ( frozen = True ) clase  NotSpecification ( BaseSpecification ):  asunto :  BaseSpecification def  is_satisfied_by ( self ,  candidato :  Cualquiera )  ->  bool :  devuelve  not  self . subject . is_satisfied_by ( candidato )

C++

plantilla < clase T > clase ISpecification { público : virtual ~ ISpecification () = predeterminado ; 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 ; };                                             plantilla < clase T > clase CompositeSpecification : pública ISpecification < T > { pública : virtual bool IsSatisfiedBy ( T Candidate ) const override = 0 ;             virtual ISpecification < T >* And ( const ISpecification < T >& Other ) const anulación ; virtual ISpecification < T >* AndNot ( const ISpecification < T >& Other ) const anulación ; virtual ISpecification < T >* Or ( const ISpecification < T >& Other ) const anulación ; virtual ISpecification < T >* OrNot ( const ISpecification < T >& Other ) const anulación ; virtual ISpecification < T >* Not () const anulación ; };                            plantilla < clase T > clase AndSpecification final : público CompositeSpecification < T > { público : const ISpecification < T >& Izquierda ; const ISpecification < T >& Derecha ;           YEspecificación ( const ISpecification < T >& InLeft , const ISpecification < T >& InRight ) : Izquierda ( InLeft ), Derecha ( InRight ) { }         bool virtual IsSatisfiedBy ( T Candidate ) const anular { devolver Izquierda . IsSatisfiedBy ( Candidate ) && Derecha . IsSatisfiedBy ( Candidate ); } };        plantilla < class T > ISpecification < T >* CompositeSpecification < T >:: Y ( const ISpecification < T >& Otro ) const { return new AndSpecification < T > ( * this , Otro ); }         plantilla < clase T > clase AndNotSpecification final : público CompositeSpecification < T > { público : const ISpecification < T >& Izquierda ; const ISpecification < T >& Derecha ;           AndNotSpecification ( const ISpecification < T >& InLeft , const ISpecification < T >& InRight ) : Izquierda ( InLeft ), Derecha ( InRight ) { }         bool virtual IsSatisfiedBy ( T Candidate ) const anular { devolver Izquierda . IsSatisfiedBy ( Candidate ) && ! Derecha . IsSatisfiedBy ( Candidate ); } };        plantilla < clase T > clase OrSpecification final : público CompositeSpecification < T > { público : const ISpecification < T >& Izquierda ; const ISpecification < T >& Derecha ;           OrSpecification ( const ISpecification < T >& InLeft , const ISpecification < T >& InRight ) : Izquierda ( InLeft ), Derecha ( InRight ) { }         virtual bool IsSatisfiedBy ( T Candidate ) const anular { devolver Izquierda . IsSatisfiedBy ( Candidate ) || Derecha . IsSatisfiedBy ( Candidate ); } };        plantilla < clase T > clase OrNotSpecification final : público CompositeSpecification < T > { público : const ISpecification < T >& Izquierda ; const ISpecification < T >& Derecha ;           OrNotSpecification ( const ISpecification < T >& InLeft , const ISpecification < T >& InRight ) : Izquierda ( InLeft ), Derecha ( InRight ) { }         bool virtual IsSatisfiedBy ( T Candidate ) const anular { devolver Izquierda . IsSatisfiedBy ( Candidate ) || ! Derecha . IsSatisfiedBy ( Candidate ); } };        plantilla < clase T > clase NotSpecification final : público CompositeSpecification < T > { público : const ISpecification < T >& Otro ;         NoEspecificación ( const IEspecificación < T >& InOther ) : Otro ( InOther ) { }     bool virtual IsSatisfiedBy ( T Candidate ) const anular { devolver ! Otro . IsSatisfiedBy ( Candidate ); } };      plantilla < class T > ISpecification < T >* CompositeSpecification < T >:: AndNot ( const ISpecification < T >& Other ) const { return new AndNotSpecification < T > ( * this , Other ); }         plantilla < class T > ISpecification < T >* CompositeSpecification < T >:: Or ( const ISpecification < T >& Other ) const { return new OrSpecification < T > ( * this , Other ); }         plantilla < class T > ISpecification < T >* CompositeSpecification < T >:: OrNot ( const ISpecification < T >& Other ) const { return new OrNotSpecification < T > ( * this , Other ); }         plantilla < class T > ISpecification < T >* CompositeSpecification < T >:: Not () const { return new NotSpecification < T > ( * this ); }      

Mecanografiado

exportar interfaz ISpecification { isSatisfiedBy ( candidato : desconocido ) : booleano ; y ( otro : ISpecification ) : ISpecification ; andNot ( otro : ISpecification ) : ISpecification ; o ( otro : ISpecification ) : ISpecification ; orNot ( otro : ISpecification ) : ISpecification ; no () : ISpecification ; }                    exportar clase abstracta CompositeSpecification implementa ISpecification { abstracto isSatisfiedBy ( candidato : desconocido ) : booleano ;           y ( otro : ISpecification ) : ISpecification { return new AndSpecification ( este , otro ); }         andNot ( otro : ISpecification ) : ISpecification { devolver nuevo AndNotSpecification ( este , otro ); }         o ( otro : ISpecification ) : ISpecification { devolver nueva OrSpecification ( este , otro ); }         orNot ( otro : ISpecification ) : ISpecification { devolver nuevo OrNotSpecification ( este , otro ); }         no () : ISpecification { devolver nuevo NotSpecification ( this ); } }      clase de exportación AndSpecification extiende CompositeSpecification { constructor ( private leftCondition : ISpecification , private rightCondition : ISpecification ) { super (); }               isSatisfiedBy ( candidato : desconocido ) : booleano { devuelve esto . Condición izquierda . isSatisfiedBy ( candidato ) && esto . Condición correcta . está satisfecho por ( candidato ); } }        clase de exportación AndNotSpecification extiende CompositeSpecification { constructor ( private leftCondition : ISpecification , private rightCondition : ISpecification ) { super (); }               isSatisfiedBy ( candidato : desconocido ) : booleano { devuelve esto . Condición izquierda . isSatisfiedBy ( candidato ) && esto . Condición correcta . isSatisfiedBy ( candidato ) !== verdadero ; } }          clase de exportación OrSpecification extiende CompositeSpecification { constructor ( private leftCondition : ISpecification , private rightCondition : ISpecification ) { super (); }               isSatisfiedBy ( candidato : desconocido ) : booleano { devuelve esto . Condición izquierda . isSatisfiedBy ( candidato ) || este . Condición correcta . está satisfecho por ( candidato ); } }        clase de exportación OrNotSpecification extiende CompositeSpecification { constructor ( private leftCondition : ISpecification , private rightCondition : ISpecification ) { super (); }               isSatisfiedBy ( candidato : desconocido ) : booleano { devuelve esto . Condición izquierda . isSatisfiedBy ( candidato ) || este . Condición correcta . isSatisfiedBy ( candidato ) !== verdadero ; } }          clase de exportación NotSpecification extiende CompositeSpecification { constructor ( private wrap : ISpecification ) { super (); }            isSatisfiedBy ( candidato : desconocido ) : booleano { return ! this . wrapper . isSatisfiedBy ( candidato ); } }      

Ejemplo de uso

En el siguiente ejemplo, las facturas se recuperan y se envían a una agencia de cobranzas si:

  1. Están atrasados,
  2. Se han enviado avisos y
  3. No están ya con la agencia de cobranzas.

Este ejemplo pretende mostrar el resultado de cómo se "encadena" la lógica.

Este ejemplo de uso supone una clase definida previamente OverdueSpecificationque se satisface cuando la fecha de vencimiento de una factura es de 30 días o más, una NoticeSentSpecificationclase que se satisface cuando se han enviado tres avisos al cliente y una InCollectionSpecificationclase que se satisface cuando ya se ha enviado una factura a la agencia de cobros. La implementación de estas clases no es importante aquí.

Utilizando estas tres especificaciones, creamos una nueva especificación llamada SendToCollectionque se cumplirá cuando una factura esté vencida, cuando se hayan enviado avisos al cliente y aún no estén en la agencia de cobranza.

var overDue = nueva EspecificaciónDeOverDue (); var noticeSent = nueva EspecificaciónDeNotificationSent (); var inCollection = nueva EspecificaciónDeInCollection ();            // Ejemplo de encadenamiento de lógica de patrones de especificación var sendToCollection = overDue . And ( noticeSent ). And ( inCollection . Not ());   var invoiceCollection = Servicio . GetInvoices ();   foreach ( var facturaActual en ColecciónFactura ) { if ( sendToCollection.IsSatisfiedBy ( facturaActual ) ) { facturaActual.SendToCollection ( ) ; } }         

Referencias

  • Evans, Eric (2004). Diseño impulsado por dominios . Addison-Wesley. pág. 224.
  • Especificaciones de Eric Evans y Martin Fowler
  • El patrón de especificaciones: una introducción por Matt Berther
  • El patrón de especificación: una introducción en cuatro partes utilizando VB.Net por Richard Dalton
  • El patrón de especificación en PHP por Moshe Brevda
  • Especificación de la doctrina Happyr en PHP por Happyr
  • El patrón de especificación en Swift por Simon Strandgaard
  • El patrón de especificación en TypeScript y JavaScript por Thiago Delgado Pinto
  • Patrón de especificación en Flash ActionScript 3 por Rolf Vreijdenberger
Obtenido de "https://es.wikipedia.org/w/index.php?title=Patrón_de_especificación&oldid=1238065670"