Ra mắt hai series mới cực hot Trí tuệ nhân tạo A đến ZPython công cụ không thể thiếu khi nghiên cứu Data science, Machine learning.

Composite Pattern từ khái niệm đến thực hành

1. Composite Pattern là gì?

Tần suất sử dụng 4/5, Composite pattern được sử dụng khá nhiều.

Composite Pattern UML Hai pattern đầu thuộc về Creational Design Pattern, tiếp theo chúng ta sẽ làm quen với Composite Pattern nó là Structural Design Pattern, là mẫu thiết kế liên quan đến cấu trúc, kết cấu của các đối tượng. Nó được áp dụng để cấu trúc một class theo tiêu chuẩn hoặc điều chỉnh cấu trúc một class đang tồn tại. Trong thực tế, một form HTML có thể chứa một hoặc nhiều các thành phần form, mỗi thành phần này sẽ có cùng các hành vi như hiển thị, kiểm tra dữ liệu, hiển thị lỗi… Nếu không áp dụng các mẫu thì chúng ta sẽ lặp đi lặp lại code rất nhiều và giải pháp cho vấn đề này là ứng dụng Composite pattern. Chúng ta tạo ra một abstract class:

abstract class FormComponent {
  abstract function add (FormComponent $obj);
  abstract function remove (FormComponent $obj);
  abstract function display();
  abstract function validate();
  abstract function showError();
}

Lớp trìu tượng ở trên có sử dụng type hinting (cách xác định dạng dữ liệu cho tham số), hai phương thức đầu chính là cách mà Composite pattern sử dụng. Mỗi lớp con sẽ kế thừa từ lớp cha và nó cần phải định nghĩa các phương thức trìu tượng được implement từ lớp cha trìu tượng. Ví dụ:

class Form extends FormComponent {
  private $_elements = array();
  function add(FormComponent $obj) {
    $this->_elements[] = $obj;
  }
  function display() {
    // Display the entire form.
  }
}
class FormElement extends FormComponent {
  function add(FormComponent $obj) {
    return $obj; // Or false.
  }
  function display() {
    // Display the element.
  }
}

Class Form định nghĩa phương thức add() được implement từ FormConponent, nó cho phép bạn thêm thành phần vào form:

$form = new Form();
$email = new FormElement();
$form->add($email);

Chú ý là FormElement cũng định nghĩa phương thức add(), nhưng phương thức này không làm gì cả, vì chúng ta không cần thêm thành phần form vào một thành phần form. Thay vào đó, phương thức add() này trả về đối tượng được thêm vào hoặc trả về một giá trị hoặc bung ra một lỗi.

2. Ví dụ áp dụng Composite Pattern trong PHP

Với ví dụ ở dạng mẫu trên, chúng ta vẫn chưa thật sự hiểu rõ về Composite pattern. Một ví dụ cụ thể tiếp theo sẽ giúp bạn hiểu chi tiết. Ví dụ dưới đây về một ứng dụng quản lý các công việc cần làm của một nhóm và của từng thành viên trong nhóm.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Ví dụ về Composite pattern</title>
</head>
<body>
    <h2>Ví dụ về Composite pattern</h2>
    <?php
    #------------ ĐỊNH NGHĨA CLASS ----------------------#
    /* Định nghĩa class WorkUnit sử dụng Composite pattern
     * Lớp có 2 thuộc tính: tasks, name.
     * Lớp có 5 phương thức: __construct(), getName(), add(), remove(), assignTask(), completeTask().
     */
    abstract class WorkUnit {
        // Các tác vụ cần làm
        protected $tasks = array();
        // Lưu tên nhân viên hoặc tên nhóm
        protected $name = NULL;

        function __construct($name) {
            $this->name = $name;
        }
        function getName() {
            return $this->name;
        }
        // Các phương thức trìu tượng cần thực hiện
        abstract function add(Employee $e);
        abstract function remove(Employee $e);
        abstract function assignTask($task);
        abstract function completeTask($task);
    }

    /* Lớp Team mở rộng từ lớp WorkUnit.
     * Lớp có 1 thuộc tính: _employees.
     * Lớp có 1 phương thức: getCount().
     */
    class Team extends WorkUnit {
        // Lưu các thành viên của nhóm
        private $_employees = array();

        // Thực hiện các phương thức trìu tượng
        function add(Employee $e) {
            $this->_employees[] = $e;
            echo "<p>{$e->getName()} gia nhập nhóm {$this->getName()}.</p>";
        }
        function remove(Employee $e) {
            $index = array_search($e, $this->_employees);
            unset($this->_employees[$index]);
            echo "<p>{$e->getName()} bị đuổi khỏi nhóm {$this->getName()}.</p>";
        }
        function assignTask($task) {
            $this->tasks[] = $task;
            echo "<p>Một tác vụ được gán cho nhóm {$this->getName()}. Nó có thể hoàn thành dễ dàng với {$this->getCount()} thành viên.</p>";
        }
        function completeTask($task) {
            $index = array_search($task, $this->tasks);
            unset($this->tasks[$index]);
            echo "<p>Nhiệm vụ '$task' đã hoàn thành bởi nhóm {$this->getName()}.</p>";
        }
        // Phương thức trả về số thành viên trong nhóm
        function getCount() {
            return count($this->_employees);
        }
    }

    /* Lớp Employee mở rộng từ lớp WorkUnit
     * Lớp không có thuộc tính và phương thức nào
     */
    class Employee extends WorkUnit {
        // Empty functions
        function add(Employee $e) {
            return false;
        }
        function remove(Employee $e) {
            return false;
        }

        // Thực hiện phương thức trìu tượng
        function assignTask($task) {
            $this->tasks[] = $task;
            echo "<p>Một tác vụ được gán cho {$this->getName()}. Tác vụ này phải được hoàn thành bởi một mình {$this->getName()}.</p>";
        }
        function completeTask($task) {
            $index = array_search($task, $this->tasks);
            unset($this->tasks[$index]);
            echo "<p>Nhiệm vụ '$task' được hoàn thành bởi {$this->getName()}. </p>";
        }

    }
    #------------ KẾT THÚC ĐỊNH NGHĨA CLASS ----------------------#

    // Tạo đối tượng
    $fontend = new Team('Fontend');
    $kulit = new Employee('Kulit');
    $evan = new Employee('Evan You');
    $taylor = new Employee('Taylor Otwell');

    // Gán nhân viên vào nhóm fontend
    $fontend->add($kulit);
    $fontend->add($evan);
    $fontend->add($taylor);

    // Gán các tác vụ cho nhóm và nhân viên
    $fontend->assignTask('Xây dựng website');
    $evan->assignTask('Xây dựng fontend');
    // Hoàn thành một tác vụ
    $fontend->completeTask('Xây dựng website');

    // Chuyển Taylor Otwell sang nhóm backend
    $fontend->remove($taylor);

    // Xóa các đối tượng
    unset($fontend, $kulit, $evan, $taylor);
    ?>
</body>
</html>

Trong ví dụ này có nhóm và nhân viên, nhóm cũng có công việc của nhóm và nhân viên có công việc của nhân viên. Áp dụng Composite Pattern giúp chúng ta nhìn nhận Nhóm cũng giống như Nhân viên, và các xử lý trên Nhóm và Nhân viên là tương tự nhau. Kết quả khi chạy file composite.php như sau:

Ví dụ về composite pattern


CÁC BÀI VIẾT KHÁC

FirebirD

Đam mê Toán học, Lập trình. Sở thích chia sẻ kiến thức, Phim hài, Bóng đá, Cà phê sáng với bạn bè.

Factory Pattern nhà máy tạo thực thể

Strategy Pattern xây dựng chiến lược trong lúc chạy

0 Bình luận trong "Composite Pattern từ khái niệm đến thực hành"

Thêm bình luận