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
 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. 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
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);
    }
}