###模式定义 对象池(也称为资源池)被用来管理对象缓存。对象池是一组已经初始化过且可以直接使用的对象集合,用户在使用对象时可以从对象池中获取对象,对其进行操作处理,并在不需要时归还给对象池而非销毁它。 若对象初始化、实例化的代价高,且需要经常实例化,但每次实例化的数量较少的情况下,使用对象池可以获得显著的性能提升。常见的使用对象池模式的技术包括线程池、数据库连接池、任务队列池、图片资源对象池等。 当然,如果要实例化的对象较小,不需要多少资源开销,就没有必要使用对象池模式了,这非但不会提升性能,反而浪费内存空间,甚至降低性能。 ###UML类图  ###示例代码 Pool.php ```php <?php namespace App\Sheji\Pool; class Pool { private $instances = array(); private $class; public function __construct($class) { $this->class = $class; } public function get() { if (count($this->instances) > 0) { return array_pop($this->instances); } return new $this->class(); } public function dispose($instance) { $this->instances[] = $instance; } } ``` Processor.php ```php <?php namespace App\Sheji\Pool; class Processor { private $pool; private $processing = 0; private $maxProcesses = 3; private $waitingQueue = []; public function __construct(Pool $pool) { $this->pool = $pool; } public function process($image) { if ($this->processing++ < $this->maxProcesses) { $this->createWorker($image); } else { $this->pushToWaitingQueue($image); } } private function createWorker($image) { $worker = $this->pool->get(); $worker->run($image, array($this, 'processDone')); } public function processDone($worker) { $this->processing--; $this->pool->dispose($worker); if (count($this->waitingQueue) > 0) { $this->createWorker($this->popFromWaitingQueue()); } } private function pushToWaitingQueue($image) { $this->waitingQueue[] = $image; } private function popFromWaitingQueue() { return array_pop($this->waitingQueue); } } ``` Worker.php ```php <?php namespace App\Sheji\Pool; class Worker { public function __construct() { // let's say that constuctor does really expensive work... // for example creates "thread" } public function run($image, array $callback) { // do something with $image... // and when it's done, execute callback call_user_func($callback, $this); } } ``` TestWorker.php ```php <?php namespace App\Sheji\Pool\Tests; class TestWorker { public $id = 1; } ``` ```php $pool = new Pool('App\Sheji\Pool\Tests\TestWorker'); $worker = $pool->get(); $this->assertEquals(1, $worker->id); $worker->id = 5; $pool->dispose($worker); $this->assertEquals(5, $pool->get()->id); $this->assertEquals(1, $pool->get()->id); ``` ###总结 - 对象被预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少对象频繁创建所占用的内存空间和初始化时间,例如数据库连接对象基本上都是创建后就被放入连接池中,后续的查询请求使用的是连接池中的对象,从而加快了查询速度。类似被放入对象池中的对象还包括Socket对象、线程对象和绘图对象(GDI对象)等。 - 在Object Pool设计模式中,主要有两个参与者:对象池的管理者和对象池的用户,用户从管理者那里获取对象,对象池对于用户来讲是透明的,但是用户必须遵守这些对象的使用规则,使用完对象后必须归还或者关闭对象,例如数据库连接对象使用完后必须关闭,否则该对象就会被一直占用着。 - 对象管理者需要维护对象池,包括初始化对象池、扩充对象池的大小、重置归还对象的状态等。 - 对象池在被初始化时,可能只有几个对象,甚至没有对象,按需创建对象能节省资源和时间,对于响应时间要求较高的情况,可以预先创建若干个对象。 - 当对象池中没有对象可供使用时,管理者一般需要使用某种策略来扩充对象池,比如将对象池的大小翻倍。另外,在多线程的情况下,可以让请求资源的线程等待,直到其他线程归还了占用的对象。 - 一般来说,对象池中的对象在逻辑状态上是相同的,如果都是无状态对象(即没有成员变量的对象),那么这些对象的管理会方便的多,否则,对象被使用后的状态重置工作就要由管理者来承担。