|
|
(не показаны 4 промежуточные версии этого же участника) |
Строка 1: |
Строка 1: |
| {{значения|Пул (значения)}}
| | '''Объектный пул''' порождающий шаблон проектирования, набор инициализированных и готовых к использованию объектов. Когда системе требуется объект, он не создаётся, а берётся из пула. Когда объект больше не нужен, он не уничтожается, а возвращается в пул. |
| {{Шаблон проектирования
| |
| |название = Объектный пул
| |
| |английское_название = Object pool
| |
| |диаграмма =
| |
| |тип = порождающий
| |
| |назначение =
| |
| |структура =
| |
| |применяется_в_случаях =
| |
| |плюсы =
| |
| |минусы =
| |
| |родственные_шаблоны =
| |
| |design_patterns = Нет
| |
| }}
| |
| '''Объектный пул''' ({{lang-en|object pool}}) — [[Порождающие шаблоны проектирования|порождающий шаблон проектирования]], набор инициализированных и готовых к использованию объектов. Когда системе требуется объект, он не создаётся, а берётся из пула. Когда объект больше не нужен, он не уничтожается, а возвращается в пул. | |
|
| |
|
| == Применение == | | == Применение == |
Строка 30: |
Строка 16: |
| # Информация о видимых объектах во многих [[компьютерная игра|компьютерных играх]] (хорошим примером является [[движок Doom]]). Эта информация актуальна только в течение одного кадра; после того, как кадр выведен, список опустошается. | | # Информация о видимых объектах во многих [[компьютерная игра|компьютерных играх]] (хорошим примером является [[движок Doom]]). Эта информация актуальна только в течение одного кадра; после того, как кадр выведен, список опустошается. |
| # Компьютерная игра для хранения всех объектов на карте, вместо того, чтобы использовать обычные механизмы распределения памяти, может завести [[массив (программирование)|массив]] такого размера, которого заведомо хватит на все объекты, и свободные ячейки держать в виде [[связный список|связного списка]]. Такая конструкция повышает скорость, уменьшает фрагментацию памяти и снижает нагрузку на [[Сборка мусора (программирование)|сборщик мусора]] (если он есть). | | # Компьютерная игра для хранения всех объектов на карте, вместо того, чтобы использовать обычные механизмы распределения памяти, может завести [[массив (программирование)|массив]] такого размера, которого заведомо хватит на все объекты, и свободные ячейки держать в виде [[связный список|связного списка]]. Такая конструкция повышает скорость, уменьшает фрагментацию памяти и снижает нагрузку на [[Сборка мусора (программирование)|сборщик мусора]] (если он есть). |
|
| |
| == Ловушки ==
| |
| {{anchor|Объектная_клоака}}
| |
| # После того, как объект возвращён, он должен вернуться в состояние, пригодное для дальнейшего использования. Если объекты после возвращения в пул оказываются в неправильном или неопределённом состоянии, такая конструкция называется '''объектной клоакой''' ({{lang-en|object cesspool}}).
| |
| # Повторное использование объектов также может привести к утечке информации. Если в объекте есть секретные данные (например, номер [[кредитная карточка|кредитной карты]]), после освобождения объекта эту информацию надо затереть.
| |
| # Многопоточный объектный пул написать не так просто.
| |
| # На 2020-е годы в языках со сбором мусора управление памятью хорошо оптимизировано под постоянное выделение-отдачу. Так что, если объект занимает только память, руководства по Java не рекомендуют пользоваться пулами: обычный <code>new</code> требует всего десять процессорных команд. А сборщики мусора часто сканируют ссылки на объекты, а не их память — потому чем больше в памяти «живых» объектов, тем ниже производительность такого сборщика.
| |
|
| |
|
| == Пример реализации == | | == Пример реализации == |
|
| |
|
| === Пример на [[Python]] === | | === Пример на [[Python]] === |
| {{Hider_hiding
| | |
| | title = Исходный текст на языке Python
| |
| | content =
| |
| <source lang='python'> | | <source lang='python'> |
| #coding: utf-8 | | #coding: utf-8 |
Строка 133: |
Строка 110: |
|
| |
|
| === Пример на [[C++]] === | | === Пример на [[C++]] === |
| {{Hider_hiding
| | |
| | title = Исходный текст на языке C++
| |
| | content =
| |
| <source lang="cpp"> | | <source lang="cpp"> |
| #include <vector> | | #include <vector> |
Строка 211: |
Строка 186: |
| } | | } |
| </source> | | </source> |
| }}
| |
| Из примера для простоты убраны [[Шаблоны C++|шаблоны]] и потокозащищенность. При необходимости использования пула в нескольких потоках следует защитить тело методов createNewObject и deleteObject от одновременного выполнения каким-либо подходящим объектом синхронизации, например, [[Критическая секция|критической секцией]] или [[мьютекс]]ом.
| |
|
| |
| === Пример на [[C Sharp#|C#]] ===
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке C#
| |
| | content =
| |
| <source lang="csharp">
| |
| namespace Digital_Patterns.Creational.Object_Pool.Soft
| |
| {
| |
| /// <summary>
| |
| /// Интерфейс для использования шаблона "Object Pool" <see cref="Object_Pool"/>
| |
| /// </summary>
| |
| /// <typeparam name="T"></typeparam>
| |
| public interface ICreation<T>
| |
| {
| |
| /// <summary>
| |
| /// Возвращает вновь созданный объект
| |
| /// </summary>
| |
| /// <returns></returns>
| |
| T Create();
| |
| }
| |
| }
| |
| </source>
| |
| }}
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке C#
| |
| | content =
| |
| <source lang="csharp">
| |
| using System;
| |
| using System.Collections;
| |
| using System.Threading;
| |
|
| |
| namespace Digital_Patterns.Creational.Object_Pool.Soft
| |
| {
| |
| /// <summary>
| |
| /// Реализация пула объектов, использующего "мягкие" ссылки
| |
| /// </summary>
| |
| /// <typeparam name="T"></typeparam>
| |
| public class ObjectPool<T> where T : class
| |
| {
| |
| /// <summary>
| |
| /// Объект синхронизации
| |
| /// </summary>
| |
| private Semaphore semaphore;
| |
|
| |
| /// <summary>
| |
| /// Коллекция содержит управляемые объекты
| |
| /// </summary>
| |
| private ArrayList pool;
| |
|
| |
| /// <summary>
| |
| /// Ссылка на объект, которому делегируется ответственность
| |
| /// за создание объектов пула
| |
| /// </summary>
| |
| private ICreation<T> creator;
| |
|
| |
| /// <summary>
| |
| /// Количество объектов, существующих в данный момент
| |
| /// </summary>
| |
| private Int32 instanceCount;
| |
|
| |
| /// <summary>
| |
| /// Максимальное количество управляемых пулом объектов
| |
| /// </summary>
| |
| private Int32 maxInstances;
| |
|
| |
| /// <summary>
| |
| /// Создание пула объектов
| |
| /// </summary>
| |
| /// <param name="creator">Объект, которому пул будет делегировать ответственность
| |
| /// за создание управляемых им объектов</param>
| |
| public ObjectPool(ICreation<T> creator)
| |
| : this(creator, Int32.MaxValue)
| |
| {
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Создание пула объектов
| |
| /// </summary>
| |
| /// <param name="creator">Объект, которому пул будет делегировать ответственность
| |
| /// за создание управляемых им объектов</param>
| |
| /// <param name="maxInstances">Максимальное количество экземпляров классов,
| |
| /// которым пул разрешает существовать одновременно
| |
| /// </param>
| |
| public ObjectPool(ICreation<T> creator, Int32 maxInstances)
| |
| {
| |
| this.creator = creator;
| |
| this.instanceCount = 0;
| |
| this.maxInstances = maxInstances;
| |
| this.pool = new ArrayList();
| |
| this.semaphore = new Semaphore(0, this.maxInstances);
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Возвращает количество объектов в пуле, ожидающих повторного
| |
| /// использования. Реальное количество может быть меньше
| |
| /// этого значения, поскольку возвращаемая
| |
| /// величина - это количество "мягких" ссылок в пуле.
| |
| /// </summary>
| |
| public Int32 Size
| |
| {
| |
| get
| |
| {
| |
| lock(pool)
| |
| {
| |
| return pool.Count;
| |
| }
| |
| }
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Возвращает количество управляемых пулом объектов,
| |
| /// существующих в данный момент
| |
| /// </summary>
| |
| public Int32 InstanceCount { get { return instanceCount; } }
| |
|
| |
| /// <summary>
| |
| /// Получить или задать максимальное количество управляемых пулом
| |
| /// объектов, которым пул разрешает существовать одновременно.
| |
| /// </summary>
| |
| public Int32 MaxInstances
| |
| {
| |
| get { return maxInstances; }
| |
| set { maxInstances = value; }
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Возвращает из пула объект. При пустом пуле будет создан
| |
| /// объект, если количество управляемых пулом объектов не
| |
| /// больше или равно значению, возвращаемому методом
| |
| /// <see cref="ObjectPool{T}.MaxInstances"/>. Если количество управляемых пулом
| |
| /// объектов превышает это значение, то данный метод возварщает null
| |
| /// </summary>
| |
| /// <returns></returns>
| |
| public T GetObject()
| |
| {
| |
| lock(pool)
| |
| {
| |
| T thisObject = RemoveObject();
| |
| if (thisObject != null)
| |
| return thisObject;
| |
|
| |
| if (InstanceCount < MaxInstances)
| |
| return CreateObject();
| |
|
| |
| return null;
| |
| }
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Возвращает из пула объект. При пустом пуле будет создан
| |
| /// объект, если количество управляемых пулом объектов не
| |
| /// больше или равно значению, возвращаемому методом
| |
| /// <see cref="ObjectPool{T}.MaxInstances"/>. Если количество управляемых пулом
| |
| /// объектов превышает это значение, то данный метод будет ждать до тех
| |
| /// пор, пока какой-нибудь объект не станет доступным для
| |
| /// повторного использования.
| |
| /// </summary>
| |
| /// <returns></returns>
| |
| public T WaitForObject()
| |
| {
| |
| lock(pool)
| |
| {
| |
| T thisObject = RemoveObject();
| |
| if (thisObject != null)
| |
| return thisObject;
| |
|
| |
| if (InstanceCount < MaxInstances)
| |
| return CreateObject();
| |
| }
| |
| semaphore.WaitOne();
| |
| return WaitForObject();
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Удаляет объект из коллекции пула и возвращает его
| |
| /// </summary>
| |
| /// <returns></returns>
| |
| private T RemoveObject()
| |
| {
| |
| while (pool.Count > 0 )
| |
| {
| |
| var refThis = (WeakReference) pool[pool.Count - 1];
| |
| pool.RemoveAt(pool.Count - 1);
| |
| var thisObject = (T)refThis.Target;
| |
| if (thisObject != null)
| |
| return thisObject;
| |
| instanceCount--;
| |
| }
| |
| return null;
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Создать объект, управляемый этим пулом
| |
| /// </summary>
| |
| /// <returns></returns>
| |
| private T CreateObject()
| |
| {
| |
| T newObject = creator.Create();
| |
| instanceCount++;
| |
| return newObject;
| |
| }
| |
|
| |
| /// <summary>
| |
| /// Освобождает объект, помещая его в пул для
| |
| /// повторного использования
| |
| /// </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.Add(refThis);
| |
| semaphore.Release();
| |
| }
| |
| }
| |
| }
| |
| }
| |
|
| |
| </source>
| |
| }}
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке C#
| |
| | content =
| |
| <source lang="csharp">
| |
| namespace Digital_Patterns.Creational.Object_Pool.Soft
| |
| {
| |
| public class Reusable
| |
| {
| |
| public Object[] Objs { get; protected set; }
| |
|
| |
| public Reusable(params Object[] objs)
| |
| {
| |
| this.Objs = objs;
| |
| }
| |
| }
| |
|
| |
| public class Creator : ICreation<Reusable>
| |
| {
| |
| private static Int32 iD = 0;
| |
|
| |
| public Reusable Create()
| |
| {
| |
| ++iD;
| |
| return new Reusable(iD);
| |
| }
| |
| }
| |
|
| |
| public class ReusablePool : ObjectPool<Reusable>
| |
| {
| |
| public ReusablePool()
| |
| : base(new Creator(), 2)
| |
| {
| |
|
| |
| }
| |
| }
| |
| }
| |
| </source>
| |
| }}
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке C#
| |
| | content =
| |
| <source lang="csharp">
| |
| using System;
| |
| using System.Threading;
| |
| using Digital_Patterns.Creational.Object_Pool.Soft;
| |
|
| |
| namespace Digital_Patterns
| |
| {
| |
| class Program
| |
| {
| |
| static void Main(string[] args)
| |
| {
| |
| Console.WriteLine(System.Reflection.MethodInfo.GetCurrentMethod().Name);
| |
| var reusablePool = new ReusablePool();
| |
|
| |
| var thrd1 = new Thread(Run);
| |
| var thrd2 = new Thread(Run);
| |
| var thisObject1 = reusablePool.GetObject();
| |
| var thisObject2 = reusablePool.GetObject();
| |
| thrd1.Start(reusablePool);
| |
| thrd2.Start(reusablePool);
| |
| ViewObject(thisObject1);
| |
| ViewObject(thisObject2);
| |
| Thread.Sleep(2000);
| |
| reusablePool.Release(thisObject1);
| |
| Thread.Sleep(2000);
| |
| reusablePool.Release(thisObject2);
| |
|
| |
| Console.ReadKey();
| |
| }
| |
|
| |
| private static void Run(Object obj)
| |
| {
| |
| Console.WriteLine("\t" + System.Reflection.MethodInfo.GetCurrentMethod().Name);
| |
| var reusablePool = (ReusablePool)obj;
| |
| Console.WriteLine("\tstart wait");
| |
| var thisObject1 = reusablePool.WaitForObject();
| |
| ViewObject(thisObject1);
| |
| Console.WriteLine("\tend wait");
| |
| reusablePool.Release(thisObject1);
| |
| }
| |
|
| |
| private static void ViewObject(Reusable thisObject)
| |
| {
| |
| foreach (var obj in thisObject.Objs)
| |
| {
| |
| Console.Write(obj.ToString() + @" ");
| |
| }
| |
| Console.WriteLine();
| |
| }
| |
| }
| |
| }
| |
|
| |
|
| |
| </source>
| |
| }}
| |
|
| |
| === Пример на [[VB.NET]] ===
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке VB.NET
| |
| | content =
| |
| <source lang="vbnet">
| |
| Namespace Digital_Patterns.Creational.Object_Pool.Soft
| |
|
| |
| ' Интерфейс для использования шаблона "Object Pool" <see cref="Object_Pool"/>
| |
| Public Interface ICreation(Of T)
| |
| ' Возвращает вновь созданный объект
| |
| Function Create() As T
| |
| End Interface
| |
|
| |
| End Namespace
| |
| </source>
| |
| }}
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке VB.NET
| |
| | content =
| |
| <source lang="vbnet">
| |
| Namespace Digital_Patterns.Creational.Object_Pool.Soft
| |
|
| |
| 'Реализация пула объектов, использующий "мягкие" ссылки
| |
| Public Class ObjectPool(Of T As Class)
| |
|
| |
| 'Объект синхронизации
| |
| Private semaphore As Semaphore
| |
|
| |
| 'Коллекция содержит управляемые объекты
| |
| Private pool As ArrayList
| |
|
| |
| 'Ссылка на объект, которому делегируется ответственность за создание объектов пула
| |
| Private creator As ICreation(Of T)
| |
|
| |
| 'Количество объектов, существующих в данный момент
| |
| Private m_instanceCount As Int32
| |
|
| |
| 'Максимальное количество управляемых пулом объектов
| |
| Private m_maxInstances As Int32
| |
|
| |
| 'Созданчие пула объектов
| |
| ' creator - объект, которому пул будет делегировать ответственность за создание управляемых им объектов
| |
| Public Sub New(ByVal creator As ICreation(Of T))
| |
| Me.New(creator, Int32.MaxValue)
| |
| End Sub
| |
|
| |
| 'Создание пула объектов
| |
| ' creator - Объект, которому пул будет делегировать ответственность за создание управляемых им объектов
| |
| ' maxInstances - Максимальное количество экземпляров класс, которым пул разрешает существовать одновременно
| |
| Public Sub New(ByVal creator As ICreation(Of T), ByVal maxInstances As Int32)
| |
| Me.creator = creator
| |
| Me.m_instanceCount = 0
| |
| Me.m_maxInstances = maxInstances
| |
| Me.pool = New ArrayList()
| |
| Me.semaphore = New Semaphore(0, Me.m_maxInstances)
| |
| End Sub
| |
|
| |
| 'Возвращает количество объектов в пуле, ожидающих повторного
| |
| 'использования. Реальное количество может быть меньше
| |
| 'этого значения, поскольку возвращаемая
| |
| 'величина - это количество "мягких" ссылок в пуле.
| |
| Public ReadOnly Property Size() As Int32
| |
| Get
| |
| SyncLock pool
| |
| Return pool.Count
| |
| End SyncLock
| |
| End Get
| |
| End Property
| |
|
| |
| 'Возвращает количество управляемых пулом объектов,
| |
| 'существующих в данный момент
| |
| Public ReadOnly Property InstanceCount() As Int32
| |
| Get
| |
| Return m_instanceCount
| |
| End Get
| |
| End Property
| |
|
| |
| 'Получить или задать максимальное количество управляемых пулом
| |
| 'объектов, которым пул разрешает существовать одновременно.
| |
| Public Property MaxInstances() As Int32
| |
| Get
| |
| Return m_maxInstances
| |
| End Get
| |
| Set(ByVal value As Int32)
| |
| m_maxInstances = value
| |
| End Set
| |
| End Property
| |
|
| |
| 'Возвращает из пула объект. При пустом пуле будет создан
| |
| 'объект, если количество управляемых пулом объектов не
| |
| 'больше или равно значению, возвращаемому методом ObjectPool{T}.MaxInstances.
| |
| 'Если количество управляемых пулом объектов превышает это значение, то данный
| |
| 'метод возварщает null
| |
| Public Function GetObject() 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
| |
|
| |
| Return Nothing
| |
| End SyncLock
| |
| End Function
| |
|
| |
| ' Возвращает из пула объект. При пустом пуле будет создан
| |
| ' объект, если количество управляемых пулом объектов не
| |
| ' больше или равно значению, возвращаемому методом ObjectPool{T}.MaxInstances
| |
| ' Если количество управляемых пулом объектов превышает это значение,
| |
| ' то данный метод будет ждать до тех пор, пока какой-нибудь объект
| |
| ' не станет доступным для повторного использования.
| |
| Public Function 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()
| |
| Return WaitForObject()
| |
| End Function
| |
|
| |
| ' Удаляет объект из коллекции пула и возвращает его
| |
| 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 IsNot Nothing Then
| |
| Return thisObject
| |
| End If
| |
| m_instanceCount -= 1
| |
| End While
| |
| Return Nothing
| |
| End Function
| |
|
| |
| ' Создать объект, управляемый этим пулом
| |
| Private Function CreateObject() As T
| |
| Dim newObject As T = creator.Create()
| |
| m_instanceCount += 1
| |
| Return newObject
| |
| End Function
| |
|
| |
| ' Освобождает объект, помещая его в пул для повторного использования
| |
| 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.Add(refThis)
| |
| semaphore.Release()
| |
| End SyncLock
| |
| End Sub
| |
| End Class
| |
| End Namespace
| |
| </source>
| |
| }}
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке VB.NET
| |
| | content =
| |
| <source lang="vbnet">
| |
| Namespace Digital_Patterns.Creational.Object_Pool.Soft
| |
|
| |
| '### Класс Reusable ####
| |
| Public Class Reusable
| |
|
| |
| Private m_Objs As Object()
| |
|
| |
| Public Sub New(ByVal ParamArray objs As Object())
| |
| Me.Objs = objs
| |
| End Sub
| |
|
| |
| Public Property Objs() As Object()
| |
| Get
| |
| Return m_Objs
| |
| End Get
| |
|
| |
| Protected Set(ByVal value As Object())
| |
| m_Objs = value
| |
| End Set
| |
| End Property
| |
| End Class
| |
|
| |
| '### Класс Creator ####
| |
| Public Class Creator
| |
| Implements ICreation(Of Reusable)
| |
|
| |
| Private Shared iD As Int32 = 0
| |
|
| |
| Public Function Create() As Reusable Implements ICreation(Of Reusable).Create
| |
| iD += 1
| |
| Return New Reusable(iD)
| |
| End Function
| |
| End Class
| |
|
| |
| '### Класс ReusablePool ####
| |
| Public Class ReusablePool
| |
| Inherits ObjectPool(Of Reusable)
| |
|
| |
| Public Sub New()
| |
| MyBase.New(New Creator(), 2)
| |
| End Sub
| |
| End Class
| |
| End Namespace
| |
| </source>
| |
| }}
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке VB.NET
| |
| | content =
| |
| <source lang="vbnet">
| |
| Imports System.Threading
| |
| Imports Digital_Patterns.Creational.Object_Pool.Soft
| |
|
| |
| Namespace Digital_Patterns
| |
| Class Program
| |
|
| |
| Shared Sub Main()
| |
| Console.WriteLine(System.Reflection.MethodInfo.GetCurrentMethod().Name)
| |
| Dim reusablePool = New ReusablePool()
| |
|
| |
| Dim thrd1 = New Thread(AddressOf Run)
| |
| Dim thrd2 = New Thread(AddressOf Run)
| |
| Dim thisObject1 = reusablePool.GetObject()
| |
| Dim thisObject2 = reusablePool.GetObject()
| |
|
| |
| thrd1.Start(reusablePool)
| |
| thrd2.Start(reusablePool)
| |
|
| |
| ViewObject(thisObject1)
| |
| ViewObject(thisObject2)
| |
|
| |
| Thread.Sleep(2000)
| |
| reusablePool.Release(thisObject1)
| |
|
| |
| Thread.Sleep(2000)
| |
| reusablePool.Release(thisObject2)
| |
|
| |
| Console.ReadKey()
| |
| End Sub
| |
|
| |
| Private Shared Sub Run(ByVal obj As [Object])
| |
| Console.WriteLine(vbTab & System.Reflection.MethodInfo.GetCurrentMethod().Name)
| |
| Dim reusablePool = DirectCast(obj, ReusablePool)
| |
|
| |
| Console.WriteLine(vbTab & "start wait")
| |
| Dim thisObject1 = reusablePool.WaitForObject()
| |
|
| |
| ViewObject(thisObject1)
| |
| Console.WriteLine(vbTab & "end wait")
| |
| reusablePool.Release(thisObject1)
| |
| End Sub
| |
|
| |
| Private Shared Sub ViewObject(ByVal thisObject As Reusable)
| |
| For Each obj As Object In thisObject.Objs
| |
| Console.Write(obj.ToString() & " ")
| |
| Next
| |
| Console.WriteLine()
| |
| End Sub
| |
| End Class
| |
| End Namespace
| |
| </source>
| |
| }}
| |
|
| |
| === Пример на [[Perl]] ===
| |
| {{Hider_hiding
| |
| | title = Исходный текст на языке Perl
| |
| | content =
| |
| <source lang='perl'>
| |
| #!/usr/bin/perl -w
| |
|
| |
| =for comment
| |
|
| |
| Модуль ObjectPool реализовывает паттерн программирования "объектный пул" путём моделирования
| |
| поведения лучника, в колчане у которого имеется ограниченное количество стрел, в результате
| |
| чего ему приходится периодически их подбирать
| |
|
| |
| Пакет описывает поведение лучника
| |
|
| |
| =cut
| |
|
| |
| package Archer {
| |
|
| |
| use Quiver; # колчан с стрелами лучника
| |
|
| |
| use strict;
| |
| use warnings;
| |
|
| |
| use constant ARROWS_NUMBER => 5; # количество стрел в колчане
| |
| use constant SLEEP_TIME => 3; # максимальный перерыв между двумя действиями (в секундах)
| |
|
| |
| # -- ** констркутор ** --
| |
| sub new {
| |
| my $class = shift;
| |
| my $self = {
| |
| quiver => Quiver->new(ARROWS_NUMBER), # объект класса "Колчан"
| |
| };
| |
| bless $self, $class;
| |
| return $self;
| |
| }
| |
|
| |
| # -- ** инициализация стрельбы ** --
| |
| sub shooting_start {
| |
| my($self) = (shift);
| |
| while (1) { # условно бесконечный цикл, в котором ведется стрельба
| |
| $self->shoot() for (0 .. rand(ARROWS_NUMBER - 1)); # случайное количество выстрелов
| |
| $self->reload() for (0 .. rand(ARROWS_NUMBER - 1)); # случайное количество возвратов отстреляных стрел
| |
| }
| |
|
| |
| }
| |
|
| |
| # -- ** выстрел ** --
| |
| sub shoot {
| |
| my($self) = (shift);
| |
| $self->{quiver}->arrow_pull(); # отправляем стрелу куда подальше
| |
| sleep rand(SLEEP_TIME); # ... и пребываем в ожидании на протяжении неопределенного промежутка времени
| |
| }
| |
|
| |
| # -- ** возвращение выпущеной стрелы ** --
| |
| sub reload {
| |
| my($self) = (shift);
| |
| $self->{quiver}->arrow_return(); # возвращаем выпущенную ранее стрелу
| |
| sleep rand(SLEEP_TIME); # и опять находимся в ожидании
| |
| }
| |
| }
| |
|
| |
| $archer = Archer->new(); # бравый стрелок берет свой колчан со стрелами
| |
| $archer->shooting_start(); # ... и начинает стрелять
| |
|
| |
| =for comment
| |
|
| |
| Пакет описывает свойства колчана, которым пользуется лучник (Archer) и в котором хранятся стрелы (Arrow)
| |
|
| |
| =cut
| |
|
| |
| package Quiver {
| |
|
| |
| use Arrow; # одна стрела из колчана
| |
|
| |
| use feature "say";
| |
| use strict;
| |
| use warnings;
| |
|
| |
|
| |
| # -- ** конструктор ** --
| |
| sub new {
| |
| my($class, $arrows_number) = (shift, shift);
| |
| my $self = {
| |
| arrows => [], # стрелы в колчане (их пока нет, но скоро они там появятся)
| |
| };
| |
| bless $self, $class;
| |
| $self->arrows_prepare($arrows_number); # загрузить стрелы в колчан
| |
| return $self;
| |
| }
| |
|
| |
| # -- ** приготовление стрел к стрельбе ** --
| |
| sub arrows_prepare {
| |
| my($self, $arrows_number) = (shift, shift);
| |
| push @{$self->{arrows}}, Arrow->new($_) for (0 .. $arrows_number - 1); # укладываем стрелы в колчан
| |
| }
| |
|
| |
| # -- ** извлечение стрелы из колчана ** --
| |
| sub arrow_pull {
| |
| my($self) = (shift);
| |
| foreach(@{$self->{arrows}}) { # для каждой стрелы проверяем, в колчане ли она
| |
| if($_->check_state()) { # и если - да
| |
| $_->pull(); # вынимаем её оттуда (и стреляем)
| |
| last; # двумя стрелами одновременно мы выстрелить не сможем
| |
| }
| |
| }
| |
| }
| |
|
| |
| # -- ** возвращение стрелы в колчан ** --
| |
| sub arrow_return {
| |
| my($self) = (shift);
| |
| foreach(@{$self->{arrows}}) { # для каждой стрелы проверяем, не выпущена ли она уже
| |
| if(!$_->check_state()) { # если в колчане такой стрелы нет
| |
| $_->return(); # идем и подбираем её
| |
| last; # в теории лучник может подобрать больше одной стрелы за раз, но автор считает иначе
| |
| }
| |
| }
| |
| }
| |
| }
| |
|
| |
| 1;
| |
|
| |
| =for comment
| |
|
| |
| Пакет описывает свойства одной отдельной стрелы, находящейся в колчане (Quiver) лучника (Archer)
| |
|
| |
| =cut
| |
|
| |
| package Arrow {
| |
|
| |
| use feature "say";
| |
| use strict;
| |
| use warnings;
| |
|
| |
| # -- ** конструктор ** --
| |
| sub new {
| |
| my $class = shift;
| |
| my $self = {
| |
| number => shift, # номер стрелы
| |
| state => 1, # состояние стрелы (1 = в колчане, 0 = где-то валяется после выстрела)
| |
| };
| |
| bless $self, $class;
| |
| return $self;
| |
| }
| |
|
| |
| # -- ** изъять стрелу из колчана ** --
| |
| sub pull {
| |
| my($self) = (shift);
| |
| $self->{state} = 0; # изменить состояние стрелы на "выпущена"
| |
| say "pulled $self->{number}"; # сообщить о том, что выстрел состоялся
| |
| }
| |
|
| |
| # -- ** вернуть стрелу обратно в колчан ** --
| |
| sub return {
| |
| my($self) = (shift);
| |
| $self->{state} = 1; # изменить состояние стрелы на "в колчане"
| |
| say "returned $self->{number}"; # сообщить о том, что стрела вернулась к лучнику
| |
| }
| |
|
| |
| # -- ** проверить состояние стрелы ** --
| |
| sub check_state {
| |
| my($self) = (shift);
| |
| return $self->{state}; # вернуть состояние стрелы (1 = в колчане, 0 = выпущена)
| |
| }
| |
| }
| |
|
| |
| 1;
| |
|
| |
| </source>
| |
| }}
| |
|
| |
|
| == Ссылки == | | == Ссылки == |
Строка 982: |
Строка 193: |
|
| |
|
| [[Категория:Структуры данных]] | | [[Категория:Структуры данных]] |
| [[Категория:Статьи с примерами кода Python]]
| |