1.4. Agrupamento (Pool)

1.4.1. Purpose

O padrão de conjunto de objetos é um padrão de design criacional de software que usa um conjunto de objetos inicializados mantidos prontos para usar – um “pool” – em vez de alocá-los e destruí-los sob demanda. Um cliente do agrupamento solicitará um objeto do pool e executará operações no objeto retornado. Quando o cliente termina, retorna o objeto, que é um tipo específico de objeto de fábrica, para o pool, em vez de destruí-lo.

O agrupamento de objetos pode oferecer um aumento significativo de desempenho em situações onde o custo de inicializar uma instância de classe é alto, a taxa de instanciação de uma classe é alta, e o número de instâncias em uso em qualquer momento é baixo. O objeto em pool é obtido em tempo previsível enquanto a criação dos novos objetos (especialmente na rede) pode levar tempo variável.

No entanto, esses benefícios são principalmente verdadeiros para objetos que são caros em relação ao tempo, como conexões de banco de dados, conexões de soquete, encadeamentos e grandes objetos gráficos, como fontes ou bitmaps. Em certas situações, o agrupamento de objetos simples (que não contém recursos externos, mas apenas ocupam memória) pode não ser eficiente e diminuir o desempenho.

1.4.2. Diagrama UML

Alt Pool UML Diagram

1.4.3. Código

Você também pode encontrar esse código no 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
47
48
<?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
<?php

declare(strict_types=1);

namespace DesignPatterns\Creational\Pool;

use DateTime;

class StringReverseWorker
{
    public function __construct()
    {
    }

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

1.4.4. Teste

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
31
32
<?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);
    }
}