1.4. Pool

1.4.1. Purpose

** Шаблонът за обект на обекти ** е софтуерен шаблон за създаване на дизайн, който използва набор от инициализирани обекти, поддържани в готовност за използване - „пул“ - вместо да ги разпределя и унищожава при поискване. Клиент на пула ще поиска обект от пула и ще извърши операции върху върнатия обект. Когато клиентът завърши, той връща обекта, който е специфичен тип фабричен обект, в пула, вместо да го унищожава.

Обединяването на обекти може да предложи значително подобрение на производителността в ситуации, когато цената за инициализиране на екземпляр на клас е висока, скоростта на създаване на екземпляр на клас е висока и броят на използваните екземпляри по всяко време е нисък. Обединеният обект се получава в предвидимо време, когато създаването на новите обекти (особено по мрежа) може да отнеме променливо време.

Тези предимства обаче важат най-вече за обекти, които са скъпи по отношение на времето, като връзки към база данни, връзки на сокети, нишки и големи графични обекти като шрифтове или растерни изображения. В определени ситуации простото обединяване на обекти (които не съдържат външни ресурси, а само заемат памет) може да не е ефективно и да намали производителността.

1.4.2. UML Диаграма

Alt Pool UML Diagram

1.4.3. Код

Можете също да намерите този код в 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. Тест

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}