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<?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. Teste

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}