Grupo de objetos

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 5 de abril de 2022; las comprobaciones requieren 4 ediciones .
Grupo de objetos
grupo de objetos
Tipo de generando
Descrito en Patrones de diseño No

Un  conjunto de objetos es un patrón de diseño generador , un conjunto de objetos inicializados y listos para usar. Cuando el sistema necesita un objeto, no lo crea, sino que lo toma del grupo. Cuando ya no se necesita un objeto, no se destruye, sino que se devuelve a la piscina.

Aplicación

La agrupación de objetos se utiliza para mejorar el rendimiento cuando es costoso crear un objeto al comienzo de un trabajo y destruirlo al final. La mejora del rendimiento es especialmente notable cuando los objetos se crean y destruyen con frecuencia, pero solo existe una pequeña cantidad de ellos al mismo tiempo.

Un conjunto de objetos es útil cuando un objeto posee recursos distintos de la memoria, como los sockets de red. O si la colección de objetos ocupa una parte significativa de la memoria de la computadora y se crea mucha " basura ".

Desbordamiento

Si no hay un solo objeto libre en el grupo, es posible una de tres estrategias:

  1. Ampliación de piscina.
  2. Negativa a crear un objeto, parada de emergencia.
  3. En el caso de un sistema multitarea , puede esperar hasta que se libere uno de los objetos.

Ejemplos

  1. Información sobre archivos abiertos en DOS .
  2. Información sobre objetos visibles en muchos juegos de computadora ( el motor Doom es un buen ejemplo ). Esta información solo es relevante para un cuadro; después de que se emite el marco, la lista se vacía.
  3. Un juego de computadora para almacenar todos los objetos en el mapa, en lugar de usar los mecanismos usuales de asignación de memoria, puede crear una matriz de tal tamaño que se sabe que es suficiente para todos los objetos y mantener celdas libres en forma de una lista enlazada. . Este diseño mejora la velocidad, reduce la fragmentación de la memoria y reduce la carga en el recolector de elementos no utilizados (si corresponde).

Trampas

  1. Después de devolver un objeto, debe volver a un estado adecuado para su uso posterior. Si los objetos, después de regresar a la piscina, se encuentran en un estado incorrecto o indeterminado, dicha construcción se denomina pozo negro de objetos . 
  2. La reutilización de objetos también puede conducir a la fuga de información. Si el objeto contiene datos secretos (por ejemplo, un número de tarjeta de crédito ), después de liberar el objeto, esta información debe sobrescribirse.
  3. Un grupo de objetos de subprocesos múltiples no es fácil de escribir.
  4. Para la década de 2020, en los lenguajes recolectados en la basura, la gestión de la memoria está bien optimizada para el retroceso constante de la asignación. Entonces, si el objeto solo ocupa memoria, los manuales de Java no recomiendan usar pools: newuno regular requiere solo diez instrucciones de procesador. Y los recolectores de basura a menudo escanean referencias de objetos, no su memoria, porque cuantos más objetos "vivos" hay en la memoria, menor es el rendimiento de dicho recolector.

Ejemplo de implementación

Ejemplo de Python

Código fuente en Python #codificación: utf-8 """ Imaginemos una situación en la que tenemos una nave que puede soportar varios disparos. Crear un objeto Disparo es costoso. Por lo tanto, los objetos de la familia Disparo se crean una vez. Y después de la vida útil, el objeto permanece en memoria """ class Shot ( objeto ): """Una entidad que puede sobrevivir a múltiples golpes""" def __init__ ( self , curso de la vida = 5 ): self . toda la vida = toda la vida def actualizar ( auto ): auto . vida útil -= 1 devuelve uno mismo . vida > 0 class ObjectPool : """Object Pool""" def __init__ ( self , ** kwargs ): """Creando el pool""" self . _clsname = kwargs [ 'nombre de clase' ] self . _args = kwargs . obtener ( 'argumentos' , []) self . _num_objects = max ( kwargs [ 'num' ], 0 ) self . _pred = kwargs [ 'update_func' ] self . _max_objects = kwargs . obtener ( 'max' , self . _num_objects ) # Crea los objetos tú mismo . _objs = [ aplicar ( self . _clsname , self . _args ) para x en el rango ( self . _num_objects )] self . _end = len ( self . _objs ) def _extend_list ( self , args ): """Agregar un lugar al grupo""" self . _objs . agregar ( aplicar ( self . _clsname , args )) self . _num_objetos += 1 def add ( self , * args ): """Agregar un objeto al grupo""" newend = self . _end + 1 # Si se alcanza el máximo, cuelga if newend > self . _max_objects : return Ninguno # Si se toman todos los lugares, agregue un lugar más si newend > len ( self . _objs ): self . _extend_list ( args ) else : self . _objs [ auto . _fin ] . restablecer ( * argumentos ) auto . _end += 1 volver a sí mismo . _fin - 1 def update ( self , * args ): """Actualizar todos los objetos en el grupo""" self . _end = partición ( self . _pred , self . _objs , 0 , self . _end , args ) return self . _final def actualizar_objeto ( x ): """Actualizar objeto""" devuelve x . actualizar () def partición ( pred , seq , first , last , * args ): """Función de ordenación de objetos""" if first > last : return 0 for i in range ( first , last ): if not pred ( seq [ i ]): break else : return last para j en el rango ( i + 1 , último ): si pred ( seq [ j ]): seq [ i ], seq [ j ] = seq [ j ], seq [ i ] i += 1 return i # Actualmente usando el pool shots = ObjectPool ( classname = Shot , update_func = update_object , num = 5 ) durante los disparos . actualizar (): pasar imprimir "¡Listo!"

Ejemplo de C++

Texto fuente en C++ #incluir <vector> objeto de clase { // ... }; clase ObjectPool { privado : struct PoolRecord { objeto * instancia ; bool en_uso ; }; std :: vector < PoolRecord > m_pool ; público : Objeto * crearNuevoObjeto () { for ( tamaño_t i = 0 ; i < m_pool . tamaño (); ++ i ) { if ( ! m_pool [ i ]. en_uso ) { m_piscina [ yo ]. en_uso = verdadero ; // transferir el objeto a la lista de usados ​​return m_pool [ i ]. instancia ; } } // si no encontramos un objeto libre, expanda el registro PoolRecord del grupo ; grabar _ instancia = nuevo objeto ; grabar _ en_uso = verdadero ; m_piscina . push_back ( registro ); registro de retorno . instancia ; } void deleteObject ( Objeto * objeto ) { // en realidad, no borramos, solo marcamos que el objeto está libre para ( size_t i = 0 ; i < m_pool . size (); ++ i ) { if ( m_pool [ i ]. instancia == objeto ) { m_piscina [ yo ]. en_uso = falso ; romper ; } } } grupo de objetos virtual ~ () { // ahora "realmente" eliminamos objetos para ( size_t i = 0 ; i < m_pool . size (); ++ i ) eliminar m_pool [ i ]. instancia ; } }; int principal () { Grupo de objetos ; para ( tamaño_t i = 0 ; i < 1000 ; ++ i ) { Objeto * objeto = piscina . crearNuevoObjeto (); // ... piscina . eliminarObjeto ( objeto ); } devolver 0 ; }

Las plantillas y la seguridad de subprocesos se han eliminado del ejemplo por simplicidad . Si necesita usar el grupo en varios subprocesos, debe proteger el cuerpo de los métodos createNewObject y deleteObject de la ejecución simultánea por parte de algún objeto de sincronización adecuado, como una sección crítica o un mutex .

Ejemplo en C#

Texto fuente en C# namespace Digital_Patterns.Creational.Object_Pool.Soft { /// <summary> /// Interfaz para usar el patrón "Object Pool" <see cref="Object_Pool"/> /// </summary> /// <typeparam name= " T"></typeparam> public interface ICreation < T > { /// <summary> /// Devuelve el objeto recién creado /// </summary> /// <returns></returns> T Create () ; } } Texto fuente en C# utilizando el sistema ; utilizando System.Collections ; utilizando System.Threading ; espacio de nombres Digital_Patterns.Creational.Object_Pool.Soft { /// <summary> /// Implementación de un grupo de objetos usando referencias flexibles /// </summary> /// <typeparam name="T"></typeparam> public class ObjectPool < T > donde T : class { /// <summary> /// Objeto de sincronización /// </summary> private Semaphore semaphore ; /// <summary> /// La colección contiene objetos administrados /// </summary> private ArrayList pool ; /// <summary> /// Referencia al objeto al que se delega la responsabilidad /// de crear los objetos del pool /// </summary> private ICreation < T > created ; /// <summary> /// El número de objetos que existen actualmente /// </summary> private Int32 instanceCount ; /// <summary> /// Número máximo de objetos administrados por el grupo /// </summary> private Int32 maxInstances ; /// <summary> /// Creación de un grupo de objetos /// </summary> /// <param name="creator">El objeto en el que el grupo delegará la responsabilidad /// de crear los objetos que administra< /param> ObjectPool público ( ICreation < T > creador ) : este ( creador , Int32 . MaxValue ) { } /// <summary> /// Creación de un grupo de objetos /// </summary> /// <param name="creator">El objeto en el que el grupo delegará la responsabilidad /// de crear los objetos que administra< /param> / // <param name="maxInstances">El número máximo de instancias de clase /// que el grupo permite que existan al mismo tiempo /// </param> public ObjectPool ( ICreation < T > creador , Int32 maxInstances ) { esto . creador = creador ; esto _ recuento de instancias = 0 ; esto _ maxInstances = maxInstances ; esto _ grupo = nueva lista de arreglos (); esto _ semáforo = nuevo Semáforo ( 0 , this . maxInstances ); } /// <summary> /// Devuelve el número de objetos en el grupo que esperan ser /// reutilizados. El número real /// puede ser menor que este valor, porque /// el valor devuelto es el número de referencias flexibles en el grupo. /// </summary> public Int32 Size { get { lock ( pool ) { return pool . contar ; } } } /// <summary> /// Devuelve el número de objetos agrupados /// que existen actualmente /// </summary> public Int32 InstanceCount { get { return instanceCount ; } } /// <summary> /// Obtenga o establezca el número máximo de /// objetos administrados que el grupo permitirá que existan al mismo tiempo. /// </summary> public Int32 MaxInstances { get { return maxInstances ; } establecer { maxInstances = valor ; } } /// <summary> /// Devuelve un objeto del grupo. Con un grupo vacío, se creará un /// objeto si el número de objetos /// administrados por el grupo no es mayor o igual que el valor /// devuelto por el <see cref="ObjectPool{T}. MaxInstances"/> método. Si la cantidad de objetos /// administrados por el grupo excede este valor, entonces este método devuelve un valor nulo /// </summary> /// <returns></returns> public T GetObject () { lock ( pool ) { T esteObjeto = QuitarObjeto ( ); if ( esteObjeto != nulo ) devuelve esteObjeto ; if ( InstanceCount < MaxInstances ) devuelve CreateObject (); devolver nulo ; } } /// <summary> /// Devuelve un objeto del grupo. Con un grupo vacío, se creará un /// objeto si el número de objetos /// administrados por el grupo no es mayor o igual que el valor /// devuelto por el <see cref="ObjectPool{T}. MaxInstances"/> método. Si el número de objetos /// administrados por el grupo excede este valor, entonces este método esperará hasta que /// algún objeto esté disponible para /// reutilizarlo. /// </summary> /// <devoluciones></devoluciones> public T WaitForObject () { lock ( pool ) { T thisObject = RemoveObject (); if ( esteObjeto != nulo ) devuelve esteObjeto ; if ( InstanceCount < MaxInstances ) devuelve CreateObject (); } semáforo . esperar uno (); devuelve WaitForObject (); } /// <summary> /// Elimina un objeto de la colección del pool y lo devuelve /// </summary> /// <returns></returns> private T RemoveObject () { while ( pool . Count > 0 ) { var refThis = ( Referencia débil ) grupo [ grupo . Cuenta - 1 ]; piscina _ RemoveAt ( pool . Count - 1 ); var esteObjeto = ( T ) refEste . objetivo ; if ( esteObjeto != nulo ) devuelve esteObjeto ; recuento de instancias --; } devuelve nulo ; } /// <summary> /// Crea un objeto administrado por este grupo /// </summary> /// <returns></returns> private T CreateObject () { T newObject = creador . crear (); recuento de instancias ++; volver nuevoObjeto ; } /// <summary> /// Libera el objeto, colocándolo en el pool para /// reutilizarlo /// </summary> /// <param name="obj"></param> /// <exception cref ="NullReferenceException"></exception> public void Release ( T obj ) { if ( obj == null ) throw new NullReferenceException (); lock ( pool ) { var refThis = new WeakReference ( obj ); piscina _ Agregar ( refEsto ); semáforo _ liberar (); } } } } Texto fuente en C# espacio de nombres Digital_Patterns.Creational.Object_Pool.Soft { public class Reusable { public Object [] Objs { get ; conjunto protegido ; } public Reutilizable ( params Object [] objs ) { this . objs = objs ; } } Creador de clase pública : ICreation < Reusable > { private static Int32 iD = 0 ; Public Reutilizable Create () { ++ iD ; devolver nuevo Reutilizable ( iD ); } } public class ReusablePool : ObjectPool < Reusable > { public ReusablePool () : base ( new Creator (), 2 ) { } } } Texto fuente en C# utilizando el sistema ; utilizando System.Threading ; utilizando Digital_Patterns.Creational.Object_Pool.Soft ; espacio de nombres Digital_Patterns { class Program { static void Main ( cadena [] args ) { Console . WriteLine ( System . Reflection . MethodInfo . GetCurrentMethod (). Name ); var reusablePool = new ReusablePool (); var thrd1 = hilo nuevo ( Ejecutar ); var thrd2 = hilo nuevo ( Ejecutar ); var thisObject1 = grupo reutilizable . ObtenerObjeto (); var thisObject2 = grupo reutilizable . ObtenerObjeto (); thrd1 . Inicio ( reutilizablePool ); thrd2 . Inicio ( reutilizablePool ); VerObjeto ( esteObjeto1 ); VerObjeto ( esteObjeto2 ); hilo _ Sueño ( 2000 ); Piscina reutilizable . Liberar ( esteObjeto1 ); hilo _ Sueño ( 2000 ); Piscina reutilizable . Liberar ( esteObjeto2 ); consola _ Clave de lectura (); } vacío estático privado Ejecutar ( Objeto obj ) { Consola . WriteLine ( "\t" + System . Reflection . MethodInfo . GetCurrentMethod (). Name ); var piscina reutilizable = ( piscina reutilizable ) obj ; consola _ WriteLine ( "\tstart esperar" ); var thisObject1 = grupo reutilizable . EsperarObjeto (); VerObjeto ( esteObjeto1 ); consola _ WriteLine ( "\tend espera" ); Piscina reutilizable . Liberar ( esteObjeto1 ); } privado estático vacío ViewObject ( Reutilizable thisObject ) { foreach ( var obj in thisObject . Objs ) { Console . Escribir ( obj . ToString () + @" " ); } Consola . escribirLinea (); } } }

Ejemplo de VB.NET

Texto fuente en lenguaje VB.NET Espacio de nombres Digital_Patterns.Creational.Object_Pool.Soft ' Interfaz para usar la plantilla "Object Pool" <see cref="Object_Pool"/> Public Interface ICreation ( Of T ) ' Devuelve el objeto recién creado Función Create () As T End Interface espacio de nombres final Texto fuente en lenguaje VB.NET Espacio de nombres Digital_Patterns.Creational.Object_Pool.Soft 'Implementación del grupo de objetos usando referencias suaves Public Class ObjectPool ( Of T As Class ) 'Sincronizar objeto Semáforo privado Como semáforo 'La colección contiene objetos administrados Grupo privado como ArrayList 'Referencia al objeto en el que se delega la responsabilidad de crear los objetos del pool Private Creator As ICreation ( Of T ) 'Número de objetos existentes actualmente Privado m_instanceCount As Int32 'Número máximo de objetos agrupados Private m_maxInstances As Int32 El creador de ' Creación de grupo de objetos ' es el objeto en el que el grupo delegará la responsabilidad de crear los objetos que administra Public Sub New ( Creador de ByVal As ICreation ( Of T )) Me . Nuevo ( creador , Int32 . MaxValue ) End Sub 'Creación de un conjunto de objetos ' creador: el objeto al que el conjunto delegará la responsabilidad de crear los objetos que administra ' maxInstances: la cantidad máxima de instancias de la clase que el conjunto permitirá que existan al mismo tiempo Public Sub New ( ByVal creador As ICreation ( Of T ), ByVal maxInstances As Int32 ) me . creador = creador Yo . m_instanceCount = 0 Yo . m_maxInstances = maxInstances Yo . pool = New ArrayList () Me . semáforo = Nuevo semáforo ( 0 , Me . m_maxInstances ) End Sub 'Devuelve el número de objetos en el grupo que esperan ser reutilizados . El número real puede ser menor que este valor, porque el valor devuelto es el número de referencias blandas en el grupo. Tamaño de propiedad de solo lectura pública () como Int32 Obtener grupo de SyncLock Grupo de retorno . Contar Fin SyncLock Fin Obtener Fin Propiedad 'Devuelve el número de objetos agrupados que existen actualmente' Public ReadOnly Property InstanceCount () As Int32 Get Return m_instanceCount End Obtener End Property Obtenga o establezca la cantidad máxima de objetos administrados por el grupo que el grupo permitirá que existan en cualquier momento. Public Property MaxInstances () As Int32 Obtener Retorno m_maxInstances End Get Set ( ByVal value As Int32 ) m_maxInstances = valor End Set End Property 'Devuelve un objeto de la piscina. Un grupo vacío creará un 'objeto si la cantidad de objetos administrados por el grupo no es mayor o igual que el valor devuelto por el método ObjectPool{T}.MaxInstances. 'Si la cantidad de objetos agrupados excede este valor, entonces este 'método devuelve nulo Public Function GetObject () As T SyncLock pool Dim thisObject As T = RemoveObject () If thisObject IsNot Nothing Then Return thisObject End If Si InstanceCount < MaxInstances Entonces devuelve CreateObject () End If No devuelve nada Finaliza la función de finalización de SyncLock ' Devuelve un objeto del grupo. Un grupo vacío creará un ' objeto si el número de objetos agrupados ' no es mayor o igual que el valor devuelto por el método ObjectPool{T}.MaxInstances ' Si el número de objetos agrupados excede este valor, ' este método esperará hasta que el objeto ' no esté disponible para su reutilización. Función pública WaitForObject () As T SyncLock pool Dim thisObject As T = RemoveObject () If thisObject IsNot Nothing Then Return thisObject End If If InstanceCount < MaxInstances Then Return CreateObject () End If End SyncLock semaphore . WaitOne () Retornar WaitForObject () Fin Función ' Elimina un objeto de la colección del grupo y lo devuelve Private Function RemoveObject () As T While pool . Count > 0 Dim refThis = DirectCast ( pool ( pool . Count - 1 ), WeakReference ) pool . RemoveAt ( pool . Count - 1 ) Dim thisObject = DirectCast ( refThis . Target , T ) Si thisObject IsNot Nothing Entonces devuelve thisObject End If m_instanceCount -= 1 End While Return Nothing End Function ' Crear un objeto administrado por este grupo Función privada CreateObject () As T Dim newObject As T = creador . Create () m_instanceCount += 1 Retorna newObject End Function ' Libera el objeto, colocándolo en el grupo para su reutilización Public Sub Release ( ByVal obj As T ) If obj Is Nothing Then Throw New NullReferenceException () End If SyncLock pool Dim refThis = New WeakReference ( obj ) pool . Añadir ( refThis ) semáforo . Release () End SyncLock End Sub End Class End Namespace Texto fuente en lenguaje VB.NET Espacio de nombres Digital_Patterns.Creational.Object_Pool.Soft '### Clase reutilizable #### Clase pública reutilizable Privado m_Objs como objeto () Public Sub New ( ByVal ParamArray objs As Object ()) Me . Objs = objs End Sub Public Property Objs () As Object () Get Return m_Objs End Get Conjunto protegido ( ByVal value As Object ()) m_Objs = value End Set End Property End Class '### Class Creator #### Public Class Creator implementa ICreation ( of Reusable ) ID compartida privada como Int32 = 0 La función pública Create () As Reusable implementa ICreation ( Of Reusable ). Crear iD += 1 Devolver nuevo reutilizable ( iD ) Finalizar función Finalizar clase '### ReusablePool Class #### Clase pública ReusablePool hereda ObjectPool ( de reutilizable ) Public Sub Nuevo () MyBase . Nuevo ( Nuevo creador (), 2 ) End Sub End Class End Namespace Texto fuente en lenguaje VB.NET Importaciones System.Threading Importaciones Digital_Patterns.Creational.Object_Pool.Soft Programa de clase de patrones digitales de espacio de nombres Consola principal secundaria compartida () . WriteLine ( System . Reflection . MethodInfo . GetCurrentMethod ( ). Name ) Dim reusablePool = New ReusablePool () Dim thrd1 = Nuevo hilo ( AddressOf Run ) Dim thrd2 = Nuevo hilo ( AddressOf Run ) Dim thisObject1 = reusablePool . GetObject () Dim thisObject2 = grupo reutilizable . ObtenerObjeto () thrd1 . Inicie ( grupo reutilizable ) thrd2 . Inicio ( reutilizablePool ) VerObjeto ( esteObjeto1 ) VerObjeto ( esteObjeto2 ) hilo _ Sleep ( 2000 ) piscina reutilizable . Liberar ( esteObjeto1 ) hilo _ Sleep ( 2000 ) piscina reutilizable . Liberar ( esteObjeto2 ) consola _ Tecla de lectura () End Sub Subejecución compartida privada ( ByVal obj As [ Objeto ] ) Consola . _ WriteLine ( vbTab & System . Reflection . MethodInfo . GetCurrentMethod (. Name ) Dim reusablePool = DirectCast ( obj , ReusablePool ) consola _ WriteLine ( vbTab & "start wait" ) Dim thisObject1 = reusablePool . EsperarObjeto () ViewObject ( esteObjeto1 ) Consola . WriteLine ( vbTab & "end wait" ) reusablePool . Liberar ( thisObject1 ) End Sub Sub ViewObject privado compartido ( ByVal thisObject como reutilizable ) para cada obj como objeto en thisObject . Consola Objs . Escribir ( obj . ToString ( ) & " " ) Consola siguiente . WriteLine () End Sub End Class End Espacio de nombres

Ejemplo de Perl

Texto fuente en Perl #!/usr/bin/perl-w = para comentar El módulo ObjectPool implementa el patrón de programación "object pool" simulando el comportamiento de un arquero que tiene un número limitado de flechas en su carcaj, por lo que debe recogerlas periódicamente. El paquete describe el comportamiento del arquero. =cortar paquete arquero { usar carcaj ; # carcaj con flechas de arquero uso estricto ; advertencias de uso ; use constante FLECHAS_NUMERO => 5 ; # número de flechas en el carcaj use constante SLEEP_TIME => 3 ; # descanso máximo entre dos acciones (en segundos) # -- ** constructor ** -- sub new { mi $clase = shift ; my $self = { carcaj => Carcaj -> nuevo ( FLECHAS_NUMERO ), # objeto de la clase "Carcaj" }; bendícete $a ti mismo , $clase ; devolver $auto ; } # -- ** inicialización de disparo ** -- sub shooting_start { my ( $self ) = ( shift ); while ( 1 ) { # ciclo condicionalmente infinito que dispara $self -> disparar () for ( 0 .. rand ( NÚMERO_FLECHAS - 1 )); # número aleatorio de disparos $self -> reload () for ( 0 .. rand ( ARROWS_NUMBER - 1 )); # número aleatorio de devoluciones de flechas disparadas } } # -- ** tiro ** -- sub tiro { my ( $self ) = ( shift ); $self -> { carcaj } -> arrow_pull (); # enviar la flecha al infierno dormir rand ( SLEEP_TIME ); # ... y espera indefinidamente } # -- ** devuelve la flecha disparada ** -- sub reload { my ( $self ) = ( shift ); $self -> { carcaj } -> arrow_return (); # devuelve la flecha disparada anteriormente sleep rand ( SLEEP_TIME ); # y otra vez estamos esperando } } $arquero = Arquero -> nuevo (); # el valiente arquero toma su carcaj de flechas $arquero -> tiro_inicio (); # ... y comienza a disparar = para comentar El paquete describe las propiedades del carcaj utilizado por el arquero (Arquero) y en el que se almacenan las flechas (Flecha) =cortar carcaj de paquete { usa la flecha ; # una flecha del carcaj usar la función "decir" ; uso estricto ; advertencias de uso ; # -- ** constructor ** -- sub new { my ( $class , $arrows_number ) = ( shift , shift ); my $self = { arrows => [] , # arrows in quiver (todavía no, pero estará allí pronto) }; bendícete $a ti mismo , $clase ; $self -> arrows_prepare ( $arrows_number ); # cargar flechas en el carcaj return $self ; } # -- ** preparar flechas para disparar ** -- sub arrows_prepare { my ( $self , $arrows_number ) = ( shift , shift ); push @ { $self -> { arrows }}, Arrow -> new ( $_ ) for ( 0 .. $arrows_number - 1 ); # pon las flechas en el carcaj } # -- ** tirar de la flecha del carcaj ** -- sub arrow_pull { my ( $self ) = ( shift ); foreach ( @ { $self -> { arrows }}) { # para cada flecha, verifique si está en el carcaj if ( $_ -> check_state ()) { # y si es así $_ -> pull (); # sacarlo de allí (y disparar) último ; # no podemos disparar dos flechas al mismo tiempo } } } # -- ** devuelve la flecha al carcaj ** -- sub arrow_return { my ( $self ) = ( shift ); foreach ( @ { $self -> { arrows }}) { # para cada flecha, verifique si ya se ha disparado if ( ! $_ -> check_state ()) { # si no hay tal flecha en el carcaj $_ -> retorno ( ); # ve y recógelo el último ; # en teoría, un arquero puede recoger más de una flecha a la vez, pero el autor piensa lo contrario } } } } 1 ; = para comentar El paquete describe las propiedades de una sola flecha que se encuentra en el carcaj de un arquero (Arquero) =cortar flecha del paquete { usar la función "decir" ; uso estricto ; advertencias de uso ; # -- ** constructor ** -- sub new { mi $clase = shift ; my $self = { number => shift , # arrow number state => 1 , # arrow state (1 = en carcaj, 0 = tirado después del disparo) }; bendícete $a ti mismo , $clase ; devolver $auto ; } # -- ** quitar la flecha del carcaj ** -- sub pull { my ( $self ) = ( shift ); $self -> { estado } = 0 ; # cambiar el estado de la flecha a "liberado" decir "tirado $self->{number}" ; # informe de que se produjo el disparo } # -- ** vuelve a colocar la flecha en el carcaj ** -- sub return { my ( $self ) = ( shift ); $self -> { estado } = 1 ; # cambia el estado de la flecha a "tembló" dice "devolvió $self->{number}" ; # informar que la flecha ha regresado al arquero } # -- ** verificar el estado de la flecha ** -- sub check_state { my ( $self ) = ( shift ); return $self -> { estado }; # devuelve el estado de la flecha (1 = tembló, 0 = soltó) } } 1 ;

Enlaces