对象池模式(Pool)

目的

对象池模式是一种提前准备了一组已经初始化了的对象『池』而不是按需创建或者销毁的创建型设计模式。对象池的客户端会向对象池中请求一个对象,然后使用这个返回的对象执行相关操作。当客户端使用完毕,它将把这个特定类型的工厂对象返回给对象池,而不是销毁掉这个对象。

在初始化实例成本高,实例化率高,可用实例不足的情况下,对象池可以极大地提升性能。在创建对象(尤其是通过网络)时间花销不确定的情况下,通过对象池在可期时间内就可以获得所需的对象。

无论如何,对象池模式在需要耗时创建对象方面,例如创建数据库连接,套接字连接,线程和大型图形对象(比方字体或位图等),使用起来都是大有裨益的。在某些情况下,简单的对象池(无外部资源,只占内存)可能效率不高,甚至会有损性能。

UML 类图

25wLqKYU4b.png

代码

你可以在 GitHub 上找到这些例子

WorkerPool.php

  1. <?php
  2. namespace DesignPatterns\Creational\Pool;
  3. class WorkerPool implements \Countable
  4. {
  5. /**
  6. * @var StringReverseWorker[]
  7. */
  8. private $occupiedWorkers = [];
  9. /**
  10. * @var StringReverseWorker[]
  11. */
  12. private $freeWorkers = [];
  13. public function get(): StringReverseWorker
  14. {
  15. if (count($this->freeWorkers) == 0) {
  16. $worker = new StringReverseWorker();
  17. } else {
  18. $worker = array_pop($this->freeWorkers);
  19. }
  20. $this->occupiedWorkers[spl_object_hash($worker)] = $worker;
  21. return $worker;
  22. }
  23. public function dispose(StringReverseWorker $worker)
  24. {
  25. $key = spl_object_hash($worker);
  26. if (isset($this->occupiedWorkers[$key])) {
  27. unset($this->occupiedWorkers[$key]);
  28. $this->freeWorkers[$key] = $worker;
  29. }
  30. }
  31. public function count(): int
  32. {
  33. return count($this->occupiedWorkers) + count($this->freeWorkers);
  34. }
  35. }

StringReverseWorker.php

  1. <?php
  2. namespace DesignPatterns\Creational\Pool;
  3. class StringReverseWorker
  4. {
  5. /**
  6. * @var \DateTime
  7. */
  8. private $createdAt;
  9. public function __construct()
  10. {
  11. $this->createdAt = new \DateTime();
  12. }
  13. public function run(string $text)
  14. {
  15. return strrev($text);
  16. }
  17. }

测试

Tests/PoolTest.php

  1. <?php
  2. namespace DesignPatterns\Creational\Pool\Tests;
  3. use DesignPatterns\Creational\Pool\WorkerPool;
  4. use PHPUnit\Framework\TestCase;
  5. class PoolTest extends TestCase
  6. {
  7. public function testCanGetNewInstancesWithGet()
  8. {
  9. $pool = new WorkerPool();
  10. $worker1 = $pool->get();
  11. $worker2 = $pool->get();
  12. $this->assertCount(2, $pool);
  13. $this->assertNotSame($worker1, $worker2);
  14. }
  15. public function testCanGetSameInstanceTwiceWhenDisposingItFirst()
  16. {
  17. $pool = new WorkerPool();
  18. $worker1 = $pool->get();
  19. $pool->dispose($worker1);
  20. $worker2 = $pool->get();
  21. $this->assertCount(1, $pool);
  22. $this->assertSame($worker1, $worker2);
  23. }
  24. }