1.4. Pool
1.4.1. Purpose
The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a “pool” – rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object, which is a specific type of factory object, to the pool rather than destroying it.
Object pooling can offer a significant performance boost in situations where the cost of initializing a class instance is high, the rate of instantiation of a class is high, and the number of instances in use at any one time is low. The pooled object is obtained in predictable time when creation of the new objects (especially over network) may take variable time.
However these benefits are mostly true for objects that are expensive with respect to time, such as database connections, socket connections, threads and large graphic objects like fonts or bitmaps. In certain situations, simple object pooling (that hold no external resources, but only occupy memory) may not be efficient and could decrease performance.
1.4.2. UML Diagram
1.4.3. Code
You can also find this code on GitHub
WorkerPool.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Creational\Pool;
6
7use Countable;
8
9class WorkerPool implements Countable
10{
11 /**
12 * @var StringReverseWorker[]
13 */
14 private array $occupiedWorkers = [];
15
16 /**
17 * @var StringReverseWorker[]
18 */
19 private array $freeWorkers = [];
20
21 public function get(): StringReverseWorker
22 {
23 if (count($this->freeWorkers) === 0) {
24 $worker = new StringReverseWorker();
25 } else {
26 $worker = array_pop($this->freeWorkers);
27 }
28
29 $this->occupiedWorkers[spl_object_hash($worker)] = $worker;
30
31 return $worker;
32 }
33
34 public function dispose(StringReverseWorker $worker): void
35 {
36 $key = spl_object_hash($worker);
37 if (isset($this->occupiedWorkers[$key])) {
38 unset($this->occupiedWorkers[$key]);
39 $this->freeWorkers[$key] = $worker;
40 }
41 }
42
43 public function count(): int
44 {
45 return count($this->occupiedWorkers) + count($this->freeWorkers);
46 }
47}
StringReverseWorker.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Creational\Pool;
6
7class StringReverseWorker
8{
9 public function run(string $text): string
10 {
11 return strrev($text);
12 }
13}
1.4.4. Test
Tests/PoolTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Creational\Pool\Tests;
6
7use DesignPatterns\Creational\Pool\WorkerPool;
8use PHPUnit\Framework\TestCase;
9
10class PoolTest extends TestCase
11{
12 public function testCanGetNewInstancesWithGet()
13 {
14 $pool = new WorkerPool();
15 $worker1 = $pool->get();
16 $worker2 = $pool->get();
17
18 $this->assertCount(2, $pool);
19 $this->assertNotSame($worker1, $worker2);
20 }
21
22 public function testCanGetSameInstanceTwiceWhenDisposingItFirst()
23 {
24 $pool = new WorkerPool();
25 $worker1 = $pool->get();
26 $pool->dispose($worker1);
27 $worker2 = $pool->get();
28
29 $this->assertCount(1, $pool);
30 $this->assertSame($worker1, $worker2);
31 }
32}