Object Pool Pattern là gì và cách sử dụng trong PHP?

Object Pool Pattern

Trong bài viết trước, chúng ta đã cùng nhau tìm hiểu về Prototype Pattern. Trong bài viết này, chúng ta sẽ tiếp tục tìm hiểu một design pattern tiếp theo cũng thuộc nhóm khởi tạo (creational patterns) mang tên “Object Pool Pattern”.

Object Pool Pattern là gì thế nhỉ?

Object Pool Pattern là một design pattern thuộc nhóm khởi tạo (creational patterns). Loại design pattern này cung cấp một kỹ thuật để tái sử dụng các đối tượng đã được khởi tạo thay vì tạo mới chúng.

Về bản chất, Object Pool Pattern cho phép gọi ra một đối tượng nào đó từ một pool để sử dụng trong một khoảng thời gian nhất định rồi trả lại về pool sau khi hoàn thành xong công việc. Trong khoảng thời gian vắng mặt của đối tượng đó, không một thành phần nào khác có thể sử dụng được cho tới khi nó được quay trở về pool. Không có gì là quá khó hiểu đúng không nào.

Nên sử dụng Object Pool Pattern khi nào vậy nhỉ?

Dưới đây là một số trường hợp chúng ta có thể cân nhắc sử dụng Object Pool Pattern để giải quyết vấn đề:

  • Khi chúng ta có nhu cầu khởi tạo và hủy một số lượng lớn các đối tượng trong thời gian ngắn, liên tục.
  • Khi chúng ta cần sử dụng các đối tượng tương tự thay vì khởi tạo một đối tượng mới một cách bừa bãi và không kiểm soát.
  • Khi chúng ta cần tạo ra các đối tượng đòi hỏi phải tiêu tốn nhiều chi phí.
  • Khi có một số client cần cùng một tài nguyên tại các thời điểm khác nhau.

Cấu trúc của Object Pool Pattern

Objects Pool Pattern bao gồm ba thành phần cơ bản là Client, PooledObjectObjectPool.

Cấu trúc của Object Pool Pattern

Trong đó:

  • Client: Lớp yêu cầu khởi tạo đối tượng thuộc lớp PooledObject để sử dụng.
  • PooledObject: Một lớp đòi hỏi nhiều thời gian và chi phí để khởi tạo hoặc một lớp cần giới hạn số lượng đối tượng được khởi tạo trong ứng dụng.
  • ObjectPool: Đây là lớp đóng vai trò quan trọng nhất của Objects Pool Pattern. Lớp này có nhiệm vụ lưu trữ danh sách các đối tượng thuộc lớp Pooled Object đã được khởi tạo và đang được sử dụng. Nó cung cấp các phương thức hỗ trợ cho việc lấy đối tượng từ Pool cũng như trả lại đối tượng về Pool sau khi sử dụng xong.

Ví dụ minh họa về Object Pool Pattern

Giả sử bạn là nhân viên thuộc bộ phận IT của công ty XYZ. Vào một ngày đẹp trời, sếp giao cho bạn nhiệm vụ phát triển một ứng dụng đơn giản cho phép quản lý trạng thái làm việc của các nhân viên trong công ty. Dưới đây là một số yêu cầu của ứng dụng mà bạn nhận được từ sếp:

Yêu cầu của ứng dụng

  1. Liệt kê danh sách các nhân viên đang làm việc
  2. Liệt kê danh sách các nhân viên đang rảnh rỗi
  3. Gọi nhân viên ra để giao việc
  4. Trả nhân viên về lại trạng thái rảnh rỗi

Cùng thử áp dụng những kiến thức về Object Pool Pattern mà chúng ta vừa tìm hiểu được để thử giải quyết bài toán đặt ra này nhé.

Trước hết, chúng ta sẽ tiến hành tạo ra lớp Employee. Lớp này đại diện cho nhân viên trong công ty cũng như tương ứng với thành phần PooledObject trong cấu trúc của Object Pool Pattern. Nội dung cài đặt cụ thể của lớp này như sau:

<?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;
     }
}
?>

Tiếp theo, chúng ta sẽ tiếp tục tạo ra một lớp mới mang tên EmployeePool. Lớp này tương ứng với thành phần ObjectPool trong cấu trúc của Object Pool Pattern. Bên trong lớp này chứa hai mảng quan trọng mang tên occupiedEmployees (lưu trữ danh sách các nhân viên đang làm việc) và freeEmployees (lưu trữ danh sách các nhân viên đang rảnh rỗi). Bên cạnh đó, nó còn chứa hai phương thức quan trọng là getEmployee() (gọi nhân viên ra để giao việc) và releaseEmployee() (trả nhân viên về lại trạng thái rảnh rỗi). Nội dung cài đặt cụ thể của lớp này như sau:

<?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;
     }
}
?>

Vậy là phần cài đặt đã xong, cùng thử gọi 2 nhân viên ra để giao việc xem kết quả mà chúng ta thu được là gì nhé.

<?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";
?>

Kết quả thu được:

Employee 1: ID = 1; Name = Chris
Employee 2: ID = 2; Name = Jane
List of occupied employees: Chris, Jane
List of free employees: (Empty)

Thử trả nhân viên thứ hai về lại trạng thái rảnh rỗi xem kết quả mới mà chúng ta thu được là gì nhé.

<?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";
?>

Kết quả thu được:

Employee 1: ID = 1; Name = Chris
Employee 2: ID = 2; Name = Jane
List of occupied employees: Chris
List of free employees: Jane

Như vậy là chúng ta đã áp dụng thành công Object Pool Pattern để giải quyết vấn đề đặt ra rồi đấy. Xem ra quá trình cài đặt loại design pattern cũng khá đơn giản và nhanh chóng đúng không nào.

Ưu và nhược điểm của Object Pool Pattern

Ưu điểm

  • Objects Pool Pattern giúp tăng hiệu suất của ứng dụng.
  • Objects Pool Pattern giúp mang lại hiệu quả đáng kể trong một vài tình huống đòi hỏi tốc độ khởi tạo một đối tượng mới phải cao.
  • Objects Pool Pattern giúp quản lý các kết nối và cung cấp một cách để tái sử dụng và chia sẻ chúng.
  • Objects Pool Pattern giúp giới hạn số lượng tối đa các đối tượng có thể được tạo ra.

Nhược điểm

  • Việc hoàn trả lại đối tượng về cho pool phụ thuộc vào Client, nếu Client quên hoàn trả lại đối tượng về cho pool đồng nghĩa với việc các thành phần khác không thể sử dụng được đối tượng đó khi cần thiết.
  • Việc trữ lại các đối tượng trong pool lâu dài mà không hủy sẽ ít nhiều gây tiêu tốn tài nguyên hệ thống.

Kết luận

Như vậy, trong bài viết này chúng ta đã cùng nhau tìm hiểu sơ lược về Objects Pool Pattern, hy vọng loại pattern này sẽ giúp ích cho các bạn trong tương lai. Trong bài viết tiếp theo của series, chúng ta sẽ cùng nhau tìm hiểu về loại design pattern đầu tiên thuộc nhóm cấu trúc (structural patterns) mang tên “Adapter Pattern”. Các bạn nhớ đón xem nhé.

Gửi phản hồi