1.4. Pula obiektów (Pool)
1.4.1. Purpose
Wzorzec Puli obiektów wzorcem, który polega na użyciu puli obiektów. Pula obiektów to zbiór zainicjowanych obiektów, które są trzymane w gotowości do użycia (zamiast je alokować lub dealokować na żądanie). Klient puli obiektów żąda obiektu z tej puli i wykonuje na tym obiekcie jakieś operacje. Po skończeniu, zamiast niszczyć obiekt - zwraca go do puli. Jest to szczególny typ obiektu fabrykującego.
Użycie puli obiektów może przyczynić się do znacznego wzrostu wydajności wtedy, gdy: koszt inicjalizacji instancji klasy jest wysoki, częstotliwość tworzenia kolejnych obiektów klasy jest wysoka, liczba instancji klas będących w użyciu jest mała. Obiekt z puli jest dostarczany w przewidywalnym czasie, podczas gdy czas tworzenia nowego obiektu (szczególnie przez sieć) może być duży.
Korzyści te są w większości odczuwalne dla takich obiektów jak: połączenia bazodanowe, połączenia gniazdowe, wątki, duże obiekty graficzne (takie jak fonty i bitmapy). Użycie puli dla prostych obiektów (które nie wskazują na zewnętrzne zasoby, lecz tylko zajmują pamięć), nie jest tak samo efektywne i może nawet obniżyć wydajność.
1.4.2. Diagram UML

1.4.3. Kod
Ten kod znajdziesz również na 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. Testy
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}