Objekt pool

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 5 april 2022; kontroller kräver 4 redigeringar .
Objekt pool
objektpool
Sorts alstrande
Beskrivs i Design Patterns Inte

En  objektpool är ett genererande designmönster , en uppsättning initierade och färdiga att använda objekt. När systemet behöver ett objekt skapas det inte, utan tas från poolen. När ett föremål inte längre behövs förstörs det inte utan återförs till poolen.

Applikation

Objektpoolning används för att förbättra prestanda när man skapar ett objekt i början av ett jobb och att förstöra det i slutet är dyrt. Prestandaförbättringen är särskilt märkbar när objekt skapas och förstörs ofta, men bara ett litet antal av dem existerar samtidigt.

En objektpool är användbar när ett objekt äger andra resurser än minne, till exempel nätverksuttag. Eller om samlingen av föremål tar upp en betydande del av datorns minne och mycket " skräp " skapas.

Overflow

Om det inte finns ett enda ledigt föremål i poolen är en av tre strategier möjlig:

  1. Poolförlängning.
  2. Vägran att skapa ett objekt, nödstopp.
  3. I fallet med ett multitasking- system kan du vänta tills ett av objekten släpps.

Exempel

  1. Information om öppna filer i DOS .
  2. Information om synliga föremål i många datorspel ( Doom-motorn är ett bra exempel ). Denna information är endast relevant för en bildruta; efter att ramen har matats ut töms listan.
  3. Ett datorspel för att lagra alla objekt på kartan, istället för att använda de vanliga minnesallokeringsmekanismerna, kan skapa en array av sådan storlek att det är känt att det räcker för alla objekt, och behålla fria celler i form av en länkad lista . Denna design förbättrar hastigheten, minskar minnesfragmentering och minskar belastningen på sophämtaren (om någon).

Fällor

  1. Efter att ett föremål har returnerats måste det återgå till ett tillstånd som är lämpligt för vidare användning. Om objekt, efter att ha återvänt till poolen, är i ett felaktigt eller obestämt tillstånd, kallas en sådan konstruktion en objektavloppsbrunn . 
  2. Återanvändning av föremål kan också leda till informationsläckage. Om objektet innehåller hemliga data (till exempel ett kreditkortsnummer ) måste denna information skrivas över efter att objektet har släppts.
  3. En flertrådig objektpool är inte lätt att skriva.
  4. För 2020-talet är minneshanteringen väl optimerad för ständig allokeringsrekyl på sopsamlade språk. Så om objektet bara upptar minne, rekommenderar Java-manualerna inte att använda pooler: en vanlig newkräver bara tio processorinstruktioner. Och sophämtare skannar ofta föremålsreferenser, inte deras minne - för ju fler "levande" föremål i minnet, desto lägre prestanda har en sådan samlare.

Implementeringsexempel

Python- exempel

Källkod i Python #coding: utf-8 """ Låt oss föreställa oss en situation där vi har ett skepp som kan motstå flera skott. Att skapa ett Shot-objekt är dyrt. Därför skapas objekt från Shot-familjen en gång. Och efter livstiden finns objektet kvar i minne. """ klass Skott ( objekt ): """En enhet som kan överleva flera träffar""" def __init__ ( själv , livstid = 5 ): själv . livstid = livstid def update ( själv ): själv . livstid -= 1 retur själv . livstid > 0 class ObjectPool : """Objektpool""" def __init__ ( self , ** kwargs ): """Skapar poolen""" self . _clsname = kwargs [ 'klassnamn' ] själv . _args = kwargs . ( 'args' , []) själv . _num_objects = max ( kwargs [ 'num' ], 0 ) själv . _pred = kwargs [ 'update_func' ] själv . _max_objects = kwargs . get ( 'max' , self . _num_objects ) # Skapa objekten själv . _objs = [ tillämpa ( self . _clsname , self . _args ) för x i intervallet ( self . _num_objects )] själv . _end = len ( själv . _objs ) def _extend_list ( self , args ): """Lägg till en plats i poolen""" self . _objs . append ( tillämpa ( self . _clsname , args )) self . _num_objekt += 1 def add ( self , * args ): """Lägg till ett objekt i poolen""" newend = self . _end + 1 # Om maxvärdet nås, lägg på om newend > self . _max_objects : return None # Om alla platser är tagna, lägg till en plats till om newend > len ( self . _objs ): self . _extend_list ( args ) else : self . _objs [ själv . _slut ] . återställ ( * args ) själv . _end += 1 retur själv . _slut - 1 def update ( self , * args ): """Uppdatera alla objekt i poolen""" self . _end = partition ( self . _pred , self . _objs , 0 , self . _end , args ) returnerar själv . _slutet def update_object ( x ): """Uppdatera objekt""" returnerar x . uppdatera () def partition ( pred , seq , first , last , * args ): """Objektsorteringsfunktion""" if first > last : return 0 för i i intervallet ( första , sista ): om inte pred ( seq [ i ]): break else : returnera sist för j i intervallet ( i + 1 , sist ): om pred ( seq [ j ]): seq [ i ], seq [ j ] = seq [ j ], seq [ i ] i += 1 return i # Använder faktiskt poolskotten = ObjectPool ( klassnamn = Skott , update_func = update_object , num = 5 ) under skott . uppdatera (): passera print "Klar!"

C++ exempel

Källtext i C++ #inkludera <vektor> klass Objekt { // ... }; klass ObjectPool { privat : strukturera PoolRecord { objekt * instans ; bool in_use ; }; std :: vektor < PoolRecord > m_pool ; offentliga : Objekt * createNewObject () { för ( size_t i = 0 ; i < m_pool . size (); ++ i ) { if ( ! m_pool [ i ]. in_use ) { m_pool [ i ]. in_use = sant ; // överför objektet till listan över använda returnerar m_pool [ i ]. instans ; } } // om vi inte hittade ett ledigt objekt, expandera sedan poolen PoolRecord- post ; spela in . instans = nytt objekt ; spela in . in_use = sant ; m_pool . push_back ( posta ); returnera rekord . instans ; } void deleteObject ( Objekt * objekt ) { // i verkligheten tar vi inte bort, utan markerar bara att objektet är ledigt för ( size_t i = 0 ; i < m_pool . size (); ++ i ) { if ( m_pool [ i ]. instans == objekt ) { m_pool [ i ]. in_use = false ; bryta ; } } } virtuell ~ ObjectPool () { // nu tar vi "verkligen" bort objekt för ( size_t i = 0 ; i < m_pool . size (); ++ i ) ta bort m_pool [ i ]. instans ; } }; int main () { Objektpool ; _ för ( storlek_t i = 0 ; i < 1000 ; ++ i ) { Objekt * objekt = pool . createNewObject (); // ... pool . deleteObject ( objekt ); } returnera 0 ; }

Mallar och trådsäkerhet har tagits bort från exemplet för enkelhets skull . Om du behöver använda poolen över flera trådar, bör du skydda kroppen av metoderna createNewObject och deleteObject från samtidig exekvering av något lämpligt synkroniseringsobjekt, till exempel en kritisk sektion eller en mutex .

Exempel i C#

Källtext i C# namnutrymme Digital_Patterns.Creational.Object_Pool.Soft { /// <summary> /// Gränssnitt för att använda mönstret "Object Pool" <see cref="Object_Pool"/> /// </summary> /// <typeparam name= " T"></typeparam> offentligt gränssnitt ICreation < T > { /// <summary> /// Returnerar det nyskapade objektet /// </summary> /// <returns></returns> T Skapa () ; } } Källtext i C# använder System ; använder System.Collections ; använder System.Threading ; namnutrymme Digital_Patterns.Creational.Object_Pool.Soft { /// <summary> /// Implementera en objektpool med hjälp av mjuka referenser /// </summary> /// <typeparam name="T"></typeparam> public class ObjectPool < T > där T : class { /// <summary> /// Synkroniseringsobjekt /// </summary> privat semafor semafor ; /// <summary> /// Samlingen innehåller hanterade objekt /// </summary> privat ArrayList pool ; /// <summary> /// Referens till objektet till vilket ansvaret /// för att skapa objekten i poolen delegeras /// </summary> privat ICreation < T > skapare ; /// <summary> /// Antalet objekt som för närvarande existerar /// </summary> private Int32 instanceCount ; /// <summary> /// Maximalt antal objekt som hanteras av poolen /// </summary> private Int32 maxInstances ; /// <summary> /// Skapa en objektpool /// </summary> /// <param name="creator">Det objekt som poolen kommer att delegera ansvaret till /// för att skapa de objekt den hanterar< /param> public ObjectPool ( ICreation < T > skapare ) : detta ( skapare , Int32 . MaxValue ) { } /// <summary> /// Skapa en objektpool /// </summary> /// <param name="creator">Det objekt som poolen kommer att delegera ansvaret till /// för att skapa de objekt den hanterar< /param> / // <param name="maxInstances">Det maximala antalet klassinstanser /// som poolen tillåter att existera samtidigt /// </param> public ObjectPool ( ICreation < T > creator , Int32 maxInstances ) { detta . skapare = skapare ; detta . instanceCount = 0 ; detta . maxInstances = maxInstances ; detta . pool = ny ArrayList (); detta . semafor = ny semafor ( 0 , detta . maxInstances ); } /// <sammanfattning> /// Returnerar antalet objekt i poolen som väntar på att /// återanvändas. Det faktiska antalet /// kan vara mindre än detta värde, eftersom /// värdet som returneras är antalet mjuka referenser i poolen. /// </summary> public Int32 Storlek { get { lock ( pool ) { return pool . räkna ; } } } /// <summary> /// Returnerar antalet poolade objekt /// som för närvarande existerar /// </summary> public Int32 InstanceCount { get { return instanceCount ; } } /// <sammanfattning> /// Hämta eller ställ in det maximala antalet /// hanterade objekt som poolen tillåter att existera samtidigt. /// </summary> public Int32 MaxInstances { get { return maxInstances ; } set { maxInstances = värde ; } } /// <sammanfattning> /// Returnerar ett objekt från poolen. Med en tom pool kommer ett ///-objekt att skapas om antalet objekt /// som hanteras av poolen inte är större än eller lika med värdet /// som returneras av <see cref="ObjectPool{T}. MaxInstances"/>-metoden. Om antalet objekt /// som hanteras av poolen överstiger detta värde, returnerar denna metod null /// </summary> /// <returns></returns> public T GetObject () { lock ( pool ) { T thisObject = RemoveObject ( ); if ( thisObject != null ) returnera dettaObject ; if ( InstanceCount < MaxInstances ) returnerar CreateObject (); returnera null ; } } /// <sammanfattning> /// Returnerar ett objekt från poolen. Med en tom pool kommer ett ///-objekt att skapas om antalet objekt /// som hanteras av poolen inte är större än eller lika med värdet /// som returneras av <see cref="ObjectPool{T}. MaxInstances"/>-metoden. Om antalet objekt /// som hanteras av poolen överstiger detta värde, kommer denna metod att vänta tills /// tills något objekt blir tillgängligt för /// återanvändning. /// </summary> /// <returns></returns> public T WaitForObject () { lock ( pool ) { T thisObject = RemoveObject (); if ( thisObject != null ) returnera dettaObject ; if ( InstanceCount < MaxInstances ) returnerar CreateObject (); } semafor . waitone (); returnera WaitForObject (); } /// <summary> /// Tar bort ett objekt från poolsamlingen och returnerar det /// </summary> /// <returns></returns> privat T RemoveObject () { while ( pool . Count > 0 ) { var refThis = ( WeakReference ) pool [ pool . Räkna - 1 ]; pool . RemoveAt ( pool . Count - 1 ); var thisObject = ( T ) refThis . Mål ; if ( thisObject != null ) returnera dettaObject ; instanceCount --; } returnera null ; } /// <summary> /// Skapa ett objekt som hanteras av denna pool /// </summary> /// <returns></returns> privat T CreateObject () { T newObject = skapare . skapa (); instanceCount ++; returnera nytt objekt ; } /// <summary> /// Frigör objektet, placerar det i poolen för /// återanvändning /// </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 ); pool . Lägg till ( refThis ); semafor . release (); } } } } Källtext i C# namnutrymme Digital_Patterns.Creational.Object_Pool.Soft { public class Reusable { public Object [] Objs { get ; skyddad uppsättning ; } public Reusable ( params Object [ ] objs ) { this . Objs = objs ; } } public class Skapare : ICreation < Återanvändbar > { private static Int32 iD = 0 ; public Reusable Create () { ++ iD ; returnera ny återanvändbar ( id ); } } public class ReusablePool : ObjectPool < Reusable > { public ReusablePool () : base ( new Creator (), 2 ) { } } } Källtext i C# använder System ; använder System.Threading ; använder Digital_Patterns.Creational.Object_Pool.Soft ; namnutrymme Digital_Patterns { class Program { static void Main ( sträng [ ] args ) { Console . WriteLine ( System . Reflection . MethodInfo . GetCurrentMethod (). Namn ); var reusablePool = new ReusablePool (); var thrd1 = ny tråd ( Kör ); var thrd2 = ny tråd ( Kör ); var thisObject1 = återanvändbar pool . GetObject (); var thisObject2 = reusablePool . GetObject (); trd1 . Start ( reusablePool ); trd2 . Start ( reusablePool ); ViewObject ( thisObject1 ); ViewObject ( thisObject2 ); tråd . Sömn ( 2000 ); återanvändbar Pool . Release ( thisObject1 ); tråd . Sömn ( 2000 ); återanvändbar Pool . Release ( thisObject2 ); Konsol . ReadKey (); } privat statisk void Kör ( Objekt obj ) { Konsol . WriteLine ( "\t" + System . Reflection . MethodInfo . GetCurrentMethod (). Namn ); var reusablePool = ( ReusablePool ) obj ; Konsol . WriteLine ( "\tstart vänta" ); var thisObject1 = återanvändbar pool . WaitForObject (); ViewObject ( thisObject1 ); Konsol . WriteLine ( "\tend wait" ); återanvändbar Pool . Release ( thisObject1 ); } private static void ViewObject ( Reusable thisObject ) { foreach ( var obj in thisObject . Objs ) { Console . Skriv ( obj . ToString () + @" " ); } Konsol . writeLine (); } } }

VB.NET exempel

Källtext på språket VB.NET Namnutrymme Digital_Patterns.Creational.Object_Pool.Soft ' Gränssnitt för att använda mallen "Object Pool" <see cref="Object_Pool"/> Public Interface ICreation ( Of T ) ' Returnerar det nyskapade objektet Funktion Create () As T End Interface avsluta namnutrymmet Källtext på språket VB.NET Namnutrymme Digital_Patterns.Creational.Object_Pool.Soft 'Implementering av objektpool med mjuka referenser Public Class ObjectPool ( Of T As Class ) 'Synkronisera objekt Privat semafor Som semafor 'Samlingen innehåller hanterade objekt Privat pool Som ArrayList 'Referens till objektet till vilket ansvaret för att skapa objekten i poolen Privat skapare Som ICreation ( Av T ) delegeras 'Antal objekt som för närvarande finns Private m_instanceCount As Int32 'Maximalt antal poolade objekt Private m_maxInstances As Int32 Skaparen av 'Object Pool Creation ' är det objekt till vilket poolen delegerar ansvaret för att skapa de objekt den hanterar Public Sub New ( ByVal creator As ICreation ( Of T )) Me . Ny ( skapare , Int32 . MaxValue ) End Sub Skapare av 'Skapa en objektpool ' - Objektet till vilket poolen delegerar ansvaret för att skapa de objekt den hanterar ' maxInstances - Det maximala antalet instanser av klassen som poolen tillåter att existera samtidigt Public Sub New ( ByVal skapare Som ICreation ( Av T ), ByVal maxInstances As Int32 ) me . skapare = skapare Jag . m_instanceCount = 0 Jag . m_maxInstances = maxInstances Me . pool = New ArrayList () Jag . semafor = Ny semafor ( 0 , Me . m_maxInstances ) End Sub 'Returnerar antalet objekt i poolen som väntar på att återanvändas . Det faktiska antalet kan vara mindre än detta 'värde, eftersom värdet som returneras är antalet mjuka referenser i poolen. Allmän skrivskyddad egendomsstorlek ( ) Som Int32 SyncLock pool Returpool . _ Count End SyncLock End Get End Property 'Returnerar antalet poolade objekt som för närvarande existerar' Public ReadOnly Property InstanceCount () As Int32 Get Return m_instanceCount End Get End Property 'Hämta eller ställ in det maximala antalet poolhanterade ' objekt som poolen tillåter att existera vid en viss tidpunkt. Public Property MaxInstances () As Int32 Get Return m_maxInstances End Get Set ( ByVal value As Int32 ) m_maxInstances = värde End Set End Property 'Returnerar ett föremål från poolen. En tom pool skapar ett 'objekt om antalet objekt som hanteras av poolen inte är större än eller lika med värdet som returneras av metoden ObjectPool{T}.MaxInstances. ' Om antalet poolade objekt överstiger detta värde, returnerar denna 'metod null Public Function GetObject () As T SyncLock pool Dim thisObject As T = RemoveObject () If thisObject IsNothing Then Return thisObject End If Om InstanceCount < MaxInstances Returnera CreateObject ( ) End If Return Nothing End SyncLock End - funktion ' Returnerar ett objekt från poolen. En tom pool kommer att skapa ett ' objekt om antalet poolade objekt ' inte är större än eller lika med värdet som returneras av ObjectPool{T}.MaxInstances-metoden ' Om antalet poolade objekt överstiger detta värde, ' kommer denna metod att vänta tills objektet inte kommer att göras tillgängligt för återanvändning. Offentlig funktion WaitForObject () As T SyncLock pool Dim thisObject As T = RemoveObject ( ) If thisObject IsNothing Sedan returnera dettaObject End If Om InstanceCount < MaxInstances Returnera sedan CreateObject () End If End SyncLock semafor . WaitOne () Returnera WaitForObject ( ) Slutfunktion ' Tar bort ett objekt från poolsamlingen och returnerar det 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 ) If thisObject IsNothing Then Return thisObject End If m_instanceCount - = 1 End While Return Nothing End Function ' Skapa ett objekt som hanteras av denna pool Privat funktion CreateObject () As T Dim newObject As T = creator . Skapa () m_instanceCount += 1 Returnera newObject End Function ' Frigör objektet och placerar det i poolen för återanvändning 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 . Lägg till ( refThis ) semafor . Släpp () End SyncLock End Sub End Class End Namespace Källtext på språket VB.NET Namnutrymme Digital_Patterns.Creational.Object_Pool.Soft '### Klass återanvändbar #### Offentlig klass återanvändbar Privata m_Objs som objekt () Public Sub New ( ByVal ParamArray objs As Object ()) Me . Objs = objs End Sub Public Property Objs () Som Objekt () Get Return m_Objs End Get Skyddad uppsättning ( ByVal värde som objekt ( ) ) m_Objs = värde Slutuppsättning Slutegenskaper Slutklass _ '### Class Creator #### Public Class Creator implementerar ICreation ( av återanvändbar ) Privat delat ID som Int32 = 0 Public Function Skapa () Som återanvändbart implementerar ICreation ( Av återanvändbar ). Skapa iD + = 1 Returnera Ny Återanvändbar ( iD ) Slutfunktion Slutklass _ '### ReusablePool Class #### Public Class ReusablePool ärver ObjectPool ( Of Reusable ) Public Sub Ny () MyBase . Ny ( Ny skapare ( ) , 2 ) Slut Sub Slutklass Slutnamnområde Källtext på språket VB.NET Importerar System.Threading Importerar Digital_Patterns.Creational.Object_Pool.Soft Namnutrymme Digital_Patterns Klassprogram _ Delad underhuvudkonsol ( ) . _ WriteLine ( System . Reflection . MethodInfo . GetCurrentMethod ( ). Namn ) Dim reusablePool = New ReusablePool () Dim thrd1 = Ny tråd ( AdressOf Run ) Dim thrd2 = Ny tråd ( AddressOf Run ) Dim thisObject1 = ReusablePool . GetObject () Dim thisObject2 = reusablePool . GetObject () trd1 . Starta ( reusablePool ) thrd2 . Starta ( återanvändbar pool ) ViewObject ( thisObject1 ) ViewObject ( thisObject2 ) tråd . Sleep ( 2000 ) återanvändbar Pool . Release ( thisObject1 ) tråd . Sleep ( 2000 ) återanvändbar Pool . Release ( thisObject2 ) Konsol . ReadKey () End Sub Privat delad delkörning ( ByVal obj As [ Object ] ) konsol . _ WriteLine ( vbTab & System . Reflection . MethodInfo . GetCurrentMethod (. Namn ) Dim reusablePool = DirectCast ( obj , ReusablePool ) Konsol . WriteLine ( vbTab & "start vänta" ) Dim thisObject1 = reusablePool . WaitForObject () ViewObject ( thisObject1 ) Console . WriteLine ( vbTab & "avsluta vänta" ) reusablePool . Släpp ( thisObject1 ) End Sub Private Shared Sub ViewObject ( ByVal thisObject As Reusable ) För varje obj As Object In thisObject . Objs konsol . Skriv ( obj . ToString () & " " ) Nästa konsol . WriteLine () End Sub End Class End Namespace

Perl- exempel

Källtext i Perl #!/usr/bin/perl -w =för kommentar ObjectPool-modulen implementerar programmeringsmönstret "objektpool" genom att simulera beteendet hos en bågskytt som har ett begränsat antal pilar i kogern, vilket resulterar i att han regelbundet måste plocka upp dem Paketet beskriver bågskyttens beteende =klippa paket bågskytt { använd Quiver ; # koger med bågskyttens pilar använd strikt ; använd varningar ; använd konstant ARROWS_NUMBER => 5 ; # antal pilar i kogret använder konstant SLEEP_TIME => 3 ; # maximal paus mellan två åtgärder (i sekunder) # -- ** konstruktor ** -- sub new { my $class = shift ; my $self = { quiver => Quiver -> new ( ARROWS_NUMBER ), # objekt av klassen "Quiver" }; välsigna $själv , $klass ; returnera $self ; } # -- ** shooting initialization ** -- sub shooting_start { my ( $self ) = ( shift ); while ( 1 ) { # villkorligt oändlig slinga som skjuter $self -> shoot () för ( 0 .. rand ( ARROWS_NUMBER - 1 )); # slumpmässigt antal skott $self -> reload () för ( 0 .. rand ( ARROWS_NUMBER - 1 )); # slumpmässigt antal returer av avfyrade pilar } } # -- ** skott ** -- sub shoot { my ( $self ) = ( shift ); $self -> { koger } -> arrow_pull (); # skicka pilen till helvetet sov rand ( SLEEP_TIME ); # ... och vänta på obestämd tid } # -- ** returnera den avfyrade pilen ** -- sub reload { my ( $self ) = ( shift ); $self -> { quiver } -> arrow_return (); # returnera den tidigare avfyrade pilen sleep rand ( SLEEP_TIME ); # och igen vi väntar } } $archer = Archer -> new (); # den modige bågskytten tar sitt pilkoger $archer -> shooting_start (); # ... och börjar fotografera =för kommentar Paketet beskriver egenskaperna för kogern som används av bågskytten (Archer) och i vilka pilar är lagrade (Arrow) =klippa paket quiver { använd pil ; # en pil från kogret använd funktionen "säg" ; använd strikt ; använd varningar ; # -- ** konstruktor ** -- sub new { my ( $ class , $ arrows_number ) = ( shift , shift ); mitt $self = { pilar => [] , # pilar i koger (inte än, men kommer snart) }; välsigna $själv , $klass ; $self -> arrows_prepare ( $arrows_number ); # ladda pilar i koger return $self ; } # -- ** förbered pilar för fotografering ** -- sub arrows_prepare { my ( $self , $arrows_number ) = ( shift , shift ); tryck @ { $self -> { arrows }}, Arrow -> new ( $_ ) för ( 0 .. $arrows_number - 1 ); # sätt pilarna i kogret } # -- ** dra pil från koger ** -- sub arrow_pull { my ( $self ) = ( shift ); foreach ( @ { $self -> { arrows }}) { # för varje pil, kontrollera om den finns i kogret if ( $_ -> check_state ()) { # och om ja $_ -> pull (); # ta ut den därifrån (och skjut) sist ; # vi kan inte avfyra två pilar samtidigt } } } # -- ** returnera pilen till quiver ** -- sub arrow_return { my ( $self ) = ( shift ); foreach ( @ { $self -> { arrows }}) { # för varje pil, kontrollera om den redan har avfyrats if ( ! $_ -> check_state ()) { # om det inte finns någon sådan pil i kogret $_ -> returnera ( ); # gå och hämta den sist ; # i teorin kan en bågskytt plocka upp mer än en pil åt gången, men författaren tycker något annat } } } } 1 ; =för kommentar Paketet beskriver egenskaperna hos en enstaka pil som finns i kogern på en bågskytt (Archer) =klippa paket Arrow { använd funktionen "säg" ; använd strikt ; använd varningar ; # -- ** konstruktor ** -- sub new { my $class = shift ; mitt $jag = { nummer => skift , # pilnummertillstånd => 1 , # piltillstånd (1 = i koger, 0 = liggande efter skott) }; välsigna $själv , $klass ; returnera $self ; } # -- ** ta bort pil från koger ** -- sub pull { my ( $self ) = ( shift ); $self -> { state } = 0 ; # ändra pilläge till "släppt" säg "drade $self->{nummer}" ; # rapportera att skottet ägde rum } # -- ** sätt tillbaka pilen i kogret ** -- sub return { my ( $self ) = ( shift ); $self -> { state } = 1 ; # ändra piltillståndet till "darrade" säg "returnerade $self->{number}" ; # rapportera att pilen har återvänt till bågskytten } # -- ** check arrow state ** -- sub check_state { my ( $self ) = ( shift ); returnera $self -> { state }; # returnera pilens tillstånd (1 = darrade, 0 = släppt) } } 1 ;

Länkar