In this article, we will learn about a design pattern that is a part of the creational patterns called "The Object Pool Pattern".
What is the Object Pool Pattern?
Object Pool Pattern is a design pattern that belongs to the initialization creational patterns. This type of design pattern provides a technique to reuse objects that have been initialized instead of creating new ones.
In essence, this one allows calling a certain object from a pool to use for a certain period of time and then return it back to the pool after the job is done. During the absence of that object, no other component can use this one until it is returned back to the pool. Nothing is too difficult to understand, right.
When should I Use the Object Pool Pattern?
Following are some cases that we might consider using to solve the problem:
- When we need to create and destroy a large number of objects continuously in a short time.
- When we need to use similar objects instead of initializing a new object indiscriminately and uncontrollably.
- When we need to create objects that require a lot of costs.
- When there are several clients who need the same resources at different times.
The Structure of the Object Pool Pattern
The Objects Pool Pattern is composed of three important components: Client, PooledObject, and ObjectPool.
- Client: The class that requires an instance of the PooledObject class to use.
- PooledObject: A class that is costly to be initialized or a class that needs to limit its number of instances in the application.
- ObjectPool: This is the class that plays the most important role in this Pattern. It is responsible for storing the list of objects that are instances of the PooledObject class. It provides a method for retrieving a specific object from the pool as well as return an object back to the pool after use.
Example of the Object Pool Pattern
Imagine you are a software developer currently working for an IT company called XYZ. One day, the boss assigned you the task of developing a simple application that is responsible for managing the working status of all the employees in your company. Following are the requirements of the application that you received from your boss:
The Application Requirements
- Get the list of employees that are currently working.
- Get the list of employees that are currently free.
- Call a free employee out to assign him a task.
- Return an employee back to his free state after he finishes his task.
Let's apply what we have learned about the Object Pool Pattern so far to provide a solution to this problem.
First of all, we will create a new class called Employee. This class will represent the employees in the company as well as corresponding to the PooledObject component in its structure. The specific definition of this class is as follows:
<?php class Employee { private $id; private $name; public function __construct($id, $name) { $this->id = $id; $this->name = $name; } public function getId() { return $this->id; } public function getName() { return $this->name; } public function getInfo() { echo "ID = " . $this->id . "; Name = " . $this->name; } } ?>
Next, we will create another class called EmployeePool. This class corresponds to the ObjectPool component structure. It contains two important arrays called occupied employees (storing the list of employees that are currently working) and freeEmployees (lưu trữ storing the list of employees that are currently free). Additionally, it also contains two other important methods called getEmployee() (calling an employee that is currently free out to assign a task) and releaseEmployee() (returning an employee back to his free state after he finishes his task). The specific definition of this class is as follows:
<?php class EmployeePool { private $occupiedEmployees; private $freeEmployees; private $names = [ 'William', 'Chris', 'Elsa', 'Jane', 'Bob' ]; public function __construct() { $this->occupiedEmployees = []; $this->freeEmployees = []; } public function getEmployee() { if (count($this->freeEmployees) == 0) { $id = count($this->occupiedEmployees) + count($this->freeEmployees) + 1; $randomName = array_rand($this->names, 1); $employee = new Employee($id, $this->names[$randomName]); } else { $employee = array_pop($this->freeEmployees); } $this->occupiedEmployees[$employee->getId()] = $employee; return $employee; } public function release($employee) { $id = $employee->getId(); if (isset($this->occupiedEmployees[$id])) { unset($this->occupiedEmployees[$id]); $this->freeEmployees[$id] = $employee; } } public function getOccupiedEmployees() { $employees = '(Empty)'; if (count($occupiedEmployees) > 0) { foreach ($occupiedEmployees as $employee) { $employees = $employees . $employee->getName(); } } return $employees; } public function getFreeEmployees() { $employees = '(Empty)'; if (count($freeEmployees) > 0) { foreach ($freeEmployees as $employee) { $employees = $employees . $employee->getName(); } } return $employees; } } ?>
So the installation is done, let's try getting 2 employees out to see what the results we will get.
<?php $pool = new EmployeePool(); $employee1 = $pool->getEmployee(); $employee2 = $pool->getEmployee(); echo "Employee 1: " .$employee1->getInfo(). "\n"; echo "Employee 2: " .$employee2->getInfo(). "\n"; echo "List of occupied employees: " .$pool->getOccupiedEmployees(). "\n"; echo "List of free employees: " .$pool->getFreeEmployees(). "\n"; ?>
Result:
Employee 1: ID = 1; Name = Chris Employee 2: ID = 2; Name = Jane List of occupied employees: Chris, Jane List of free employees: (Empty)
Let’s try returning the second employee to his free state and see what new results we will get.
<?php $pool = new EmployeePool(); $employee1 = $pool.getEmployee(); $employee2 = $pool.getEmployee(); $pool->release($employee2); echo "Employee 1: " .$employee1->getInfo(). "\n"; echo "Employee 2: " .$employee2->getInfo(). "\n"; echo "List of occupied employees: " .$pool->getOccupiedEmployees(). "\n"; echo "List of free employees: " .$pool->getFreeEmployees(). "\n"; ?>
Result:
Employee 1: ID = 1; Name = Chris Employee 2: ID = 2; Name = Jane List of occupied employees: Chris List of free employees: Jane
So we have successfully applied the Object Pool Pattern to solve our given problem. It seems that the installation process of the design pattern is quite simple and fast, right?
The Pros and Cons of the Object Pool Pattern
Pros
- The Object Pool Pattern helps increase the overall performance of the application.
- The Object Pool Pattern helps achieve high initialization speed of a new object in some situations.
- The Object Pool Pattern helps manage connections and provides a way to reuse and share them.
- The Object Pool Pattern helps limit the maximum number of objects that can be created.
Cons
- The return of the object back to the pool is completely dependent on the Client. If the Client forgets to return the object back to the pool, then other components cannot use that object when they need it.
- The retainment of multiple objects in the pool for a long time without destroying them will more or less consume system resources.
Conclusion
In this article, we have had a brief look at the Object Pool Pattern, hoping that this one will help you in the future. In the next article of this series, we will learn about the first design pattern of the structural patterns called "The Adapter Pattern". Stay tuned!