1.4. Pool

1.4.1. Purpose

Object pool pattern utilise un ensemble d’objets initialisés et prêts à être utilisés - un « pool » - plutôt que de les allouer et de les détruire à la demande. Un client du pool demandera un objet du pool et effectuera des opérations sur l’objet retourné. Lorsque le client a terminé, il renvoie l’objet, qui est au pool plutôt que de le détruire.

La mise en commun d’objets peut offrir un gain de performance significatif dans les situations où le coût d’initialisation d’une instance de classe est élevé, le taux d’instanciation d’une classe est élevé et le nombre d’instances utilisées à un moment donné est faible. L’objet mis en commun est obtenu en un temps prévisible alors que la création des nouveaux objets (notamment sur le réseau) peut prendre un temps variable.

Toutefois, ces avantages s’appliquent surtout aux objets qui sont coûteux en temps, tels que les connexions aux bases de données, les connexions aux sockets, les threads et les gros objets graphiques comme les polices ou les bitmaps. Dans certaines situations, la mise en commun d’objets simples (qui ne détiennent aucune ressource externe, mais occupent seulement la mémoire) peut ne pas être efficace et pourrait diminuer les performances.

1.4.2. Diagramme UML

Alt Pool UML Diagram

1.4.3. Code

Vous pouvez également trouver ce code sur 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}