1.4. 对象池
1.4.1. Purpose
对象池设计模式 是一种创建型设计模式。它使用一组提前已准备完成可以使用的对象,而不是根据需要分配或销毁。这种来源被称为:“池”(pool)。池的使用者将从池中请求一个对象,并对返回的对象进行操作。在客户端处理完成后,它将返回一种特定类型的工厂对象。返回给池,而不是销毁。
对象池模式在一些情景下可以带来明显的性能提升。如:类实例初始化成本较高、类的实例化率较高、或类实例同时使用率不高的情况下。当创建新对象(尤其是通过网络)的时间花费不确定时,池对象的获得时间却是可预测的。
这些优点对于时间要求敏感的对象来说,是非常有用的。例如:数据库连接、套接字连接、线程和大型图形对象(如字体或位图)。但在某些情况下,简单的对象池(不包含外部资源,只占用内存)可能效率不高,并且会降低性能。
1.4.2. UML 图

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}