1.4. Pool

1.4.1. Purpose

Il pool pattern è un pattern creazionale che inizializza un insieme di oggetti e li tiene pronti all’uso all’interno di una – «pool» – invece diallocarli e deallocarli su richiesta. Il client che usa la pool richiederà un oggetto al suo interno su cui effettuare delle operazioni. Una volta che ha concluso l’oggetto, il quale è un tipo particolare di factory, sarà restituito alla pool invece che distrutto.

Il pooling degli oggetti può offrire un aumento delle prestazioni significative in situazioni dove il costo per inizializzare un’istanza di una classe è alto, la percentuale di istanziazione è alta e il numero di istanze in uso in qualune momento è basso. L’oggetto ottenuto dalla pool ha tempi prevedibili quando la creazione di nuovi oggetti (soprattuto in rete) richiede del tempo.

Tuttavia questi benefici valgono per oggetti che impiegano tempo per essere creati come connessioni alla base di dati, socket, thread e oggetti come font e bitmap. In alcune situazioni il semplice pooling degli oggetti (ovvero non mantengono risorse esterne ma occupano solo memoria) può non essere efficiente e far calare le prestazioni.

1.4.2. Diagramma UML

Alt Pool UML Diagram

1.4.3. Codice

Potete trovare questo codice anche su 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}