1.5. Pool

1.5.1. Purpose

The object pool pattern is a software creational design pattern thatuses a set of initialized objects kept ready to use – a “pool” – ratherthan allocating and destroying them on demand. A client of the pool willrequest an object from the pool and perform operations on the returnedobject. When the client has finished, it returns the object, which is aspecific type of factory object, to the pool rather than destroying it.

Object pooling can offer a significant performance boost in situationswhere the cost of initializing a class instance is high, the rate ofinstantiation of a class is high, and the number of instances in use atany one time is low. The pooled object is obtained in predictable timewhen creation of the new objects (especially over network) may takevariable time.

However these benefits are mostly true for objects that are expensivewith respect to time, such as database connections, socket connections,threads and large graphic objects like fonts or bitmaps. In certainsituations, simple object pooling (that hold no external resources, butonly occupy memory) may not be efficient and could decrease performance.

1.5.2. UML Diagram

Alt Pool UML Diagram

1.5.3. Code

You can also find this code on GitHub

WorkerPool.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Pool;
  4.  
  5. class WorkerPool implements \Countable
  6. {
  7. /**
  8. * @var StringReverseWorker[]
  9. */
  10. private $occupiedWorkers = [];
  11.  
  12. /**
  13. * @var StringReverseWorker[]
  14. */
  15. private $freeWorkers = [];
  16.  
  17. public function get(): StringReverseWorker
  18. {
  19. if (count($this->freeWorkers) == 0) {
  20. $worker = new StringReverseWorker();
  21. } else {
  22. $worker = array_pop($this->freeWorkers);
  23. }
  24.  
  25. $this->occupiedWorkers[spl_object_hash($worker)] = $worker;
  26.  
  27. return $worker;
  28. }
  29.  
  30. public function dispose(StringReverseWorker $worker)
  31. {
  32. $key = spl_object_hash($worker);
  33.  
  34. if (isset($this->occupiedWorkers[$key])) {
  35. unset($this->occupiedWorkers[$key]);
  36. $this->freeWorkers[$key] = $worker;
  37. }
  38. }
  39.  
  40. public function count(): int
  41. {
  42. return count($this->occupiedWorkers) + count($this->freeWorkers);
  43. }
  44. }

StringReverseWorker.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Pool;
  4.  
  5. class StringReverseWorker
  6. {
  7. /**
  8. * @var \DateTime
  9. */
  10. private $createdAt;
  11.  
  12. public function __construct()
  13. {
  14. $this->createdAt = new \DateTime();
  15. }
  16.  
  17. public function run(string $text)
  18. {
  19. return strrev($text);
  20. }
  21. }

1.5.4. Test

Tests/PoolTest.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Pool\Tests;
  4.  
  5. use DesignPatterns\Creational\Pool\WorkerPool;
  6. use PHPUnit\Framework\TestCase;
  7.  
  8. class PoolTest extends TestCase
  9. {
  10. public function testCanGetNewInstancesWithGet()
  11. {
  12. $pool = new WorkerPool();
  13. $worker1 = $pool->get();
  14. $worker2 = $pool->get();
  15.  
  16. $this->assertCount(2, $pool);
  17. $this->assertNotSame($worker1, $worker2);
  18. }
  19.  
  20. public function testCanGetSameInstanceTwiceWhenDisposingItFirst()
  21. {
  22. $pool = new WorkerPool();
  23. $worker1 = $pool->get();
  24. $pool->dispose($worker1);
  25. $worker2 = $pool->get();
  26.  
  27. $this->assertCount(1, $pool);
  28. $this->assertSame($worker1, $worker2);
  29. }
  30. }