对象池模式
目的
对象池模式是一种创建型设计模式(译者注:该模式不是 23 种经典模式之一,因此,把它放在划分到扩展模式分类下),它使用一组随时准备使用的初始化对象 — 池,而不是按需分配和销毁它们。客户端将从对象池中请求一个对象,并对返回的对象执行操作。当客户端完成后,它将对象(这是一种特定类型的工厂对象)返回到池中,而不是销毁它。
以下几种场景,使用对象池可以显著地提升性能:
- 初始化一个类实例的成本很高
- 类的实例化频率很高
- 使用的实例数量很低(任何时候)
当创建新对象(特别是通过网络)可能需要不定的时间时,可以在可预测的时间内获得池化对象。
然而,这些好处主要是对那些时间开销昂贵的对象而言,如:数据库连接、套接字连接、线程和字体或位图等大型图形对象。在某些情况下,简单的对象池(不持有外部资源,只占用内存)可能并不高效,而且可能会降低性能。
UML 类图

代码
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
| <?php declare(strict_types = 1);
namespace DesignPatterns\Extend\Pool;
use Countable;
class WorkerPool implements Countable {
private array $occupiedWorkers = [];
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 20
| <?php declare(strict_types = 1);
namespace DesignPatterns\Extend\Pool;
use DateTime;
class StringReverseWorker { private DateTime $createdAt;
public function __construct() { $this->createdAt = new DateTime(); }
public function run(string $text) { return strrev($text); } }
|
测试
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
| <?php declare(strict_types = 1);
namespace DesignPatterns\Extend\Pool\Tests;
use DesignPatterns\Extend\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); } }
|