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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php declare(strict_types=1);

namespace DesignPatterns\Creational\Pool;

use Countable;

class WorkerPool implements Countable
{
    /**
     * @var StringReverseWorker[]
     */
    private array $occupiedWorkers = [];

    /**
     * @var StringReverseWorker[]
     */
    private array $freeWorkers = [];

    public function get(): StringReverseWorker
    {
        if (count($this->freeWorkers) == 0) {
            $worker = new StringReverseWorker();
        } else {
            $worker = array_pop($this->freeWorkers);
        }

        $this->occupiedWorkers[spl_object_hash($worker)] = $worker;

        return $worker;
    }

    public function dispose(StringReverseWorker $worker)
    {
        $key = spl_object_hash($worker);

        if (isset($this->occupiedWorkers[$key])) {
            unset($this->occupiedWorkers[$key]);
            $this->freeWorkers[$key] = $worker;
        }
    }

    public function count(): int
    {
        return count($this->occupiedWorkers) + count($this->freeWorkers);
    }
}

StringReverseWorker.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php declare(strict_types=1);

namespace DesignPatterns\Creational\Pool;

use DateTime;

class StringReverseWorker
{
    private DateTime $createdAt;

    public function __construct()
    {
        $this->createdAt = new DateTime();
    }

    public function run(string $text)
    {
        return strrev($text);
    }
}

1.4.4. Test

Tests/PoolTest.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php declare(strict_types=1);

namespace DesignPatterns\Creational\Pool\Tests;

use DesignPatterns\Creational\Pool\WorkerPool;
use PHPUnit\Framework\TestCase;

class PoolTest extends TestCase
{
    public function testCanGetNewInstancesWithGet()
    {
        $pool = new WorkerPool();
        $worker1 = $pool->get();
        $worker2 = $pool->get();

        $this->assertCount(2, $pool);
        $this->assertNotSame($worker1, $worker2);
    }

    public function testCanGetSameInstanceTwiceWhenDisposingItFirst()
    {
        $pool = new WorkerPool();
        $worker1 = $pool->get();
        $pool->dispose($worker1);
        $worker2 = $pool->get();

        $this->assertCount(1, $pool);
        $this->assertSame($worker1, $worker2);
    }
}