1.4. Pila

1.4.1. Propósito

El Patrón Pila es un patrón de diseño creacional que utiliza un conjunto de objetos inicializados y los mantiene listos para usar -la «pila»- en lugar de crearlos y destruirlos bajo demanda. Un cliente puede pedirle a la pila un objeto y realizar las operaciones necesarias sobre él. Cuando el cliente ha terminado devuelve el objeto a la pila en lugar de destruirlo.

Mantener los objetos en una pila puede ofrecer mejoras significativas de rendimiento en aquellas situaciones donde el coste de inicializar las instancias es alto, el volumen de veces que se instancia la clase es alto y el número de instancias que se mantienen en uso a la vez es bajo. El objeto puede recuperarse de la pila en una cantidad de tiempo predecible, cuando la creación de nuevos objetos (especialmente cuando se realiza a través de una red) puede variar.

Sin embargo, estos beneficios son en su mayoría ciertos para objetos que son costosos con respecto al tiempo, como las conexiones de base de datos, conexiones de socket, hilos y objetos gráficos grandes como fuentes o mapas de bits. En algunas situaciones, una pila simple de objetos (que no contienen recursos externos, sino solamente ocupan memoria) puede no ser eficiente y puede ocasionar una disminución de rendimiento.

1.4.2. Diagrama UML

Alt Pool UML Diagram

1.4.3. Código

Puedes encontrar el código en 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}