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.

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

1. Factory Pattern là gì?

Tần suất sử dụng: 5/5, Factory Pattern được sử dụng cực nhiều trong lập trình. Factory pattern cũng như Singleton pattern thuộc về dạng Creational Design Pattern, tuy nhiên có một chút khác biệt. Singleton pattern áp dụng để tạo và quản lý một đối tượng duy nhất của một class trong khi Factory pattern được sử dụng để có thể tạo ra nhiều đối tượng khác nhau từ nhiều class. Tại sao cần Factory pattern trong khi chúng ta có thể tạo được đối tượng từ Singleton Pattern? Vấn đề là ở chỗ đôi khi chúng ta không biết trước được là muốn tạo đối tượng từ class cụ thể nào, do đó việc chỉ định class để tạo ra đối tượng cần phải được gán động. Sơ đồ UML của Factory Pattern như sau:

Factory pattern UML

Factory pattern cần sử dụng một lớp trìu tượng (abstract class) và có một phương thức static, được quy ước tên là Create(), factory(), factoryMethod() hoặc createInstance(). Phương thức này có một tham số để nhận biết dạng đối tượng cần tạo và trả về đối tượng này.

static function Create($type) {
  // Kiểm tra tham số $type và tạo đối tượng từ class tương ứng để trả về.
  return new SomeClassType();
}

2. Ví dụ về Factory Pattern trong PHP

Có vẻ chưa hiểu lắm, không sao, ví dụ tiếp theo sẽ giúp bạn hiểu ngay thôi. Chúng ta quay trở lại ví dụ về các hình chữ nhật (rectangle), hình tam giác (triangle) (Xem Phần 3 của Lập trình hướng đối tượng trong PHP, ví dụ đầu tiên). Chúng ta tạo ra file factory.php trong thư mục oop\pattern với nội dung như sau:

<!doctype html>
<html lang="vi">
<head>
    <meta charset="utf-8">
    <title>Ví dụ về Factory pattern</title>
</head>
<body>
    <?php
    #------------ ĐỊNH NGHĨA CLASS ----------------------#
    /* Định nghĩa class ShapeFactory sử dụng Factory pattern
     * The class contains no attributes.
     * The class contains one method: Create().
     */
    abstract class ShapeFactory {
        // Phương thức static để tạo đối tượng
        static function Create($type, array $sizes) {
            // Xác định dạng đối tượng theo tham số nhận vào
            switch ($type) {
                case 'rectangle':
                    return new Rectangle($sizes[0], $sizes[1]);
                    break;
                case 'triangle':
                    return new Triangle($sizes[0], $sizes[1], $sizes[2]);
                    break;
            }
        }
    }

    /* Định nghĩa lớp trìu tượng Shape
     * Lớp Shape không có thuộc tính
     * Lớp Shape có 2 phương thức trìu tượng:
     * - getArea()
     * - getPerimeter()
    */
    abstract class Shape {
        abstract protected function getArea();
        abstract protected function getPerimeter();
    }

    /* Định nghĩa lớp Triangle
     * Lớp Triangle có 2 thuộc tính:
     * - private $_sides (array)
     * - private $_perimeter (number)
     * Lớp Triangle có 3 phương thức:
     * - _ _construct()
     * - getArea()
     * - getPerimeter()
     */
    class Triangle extends Shape {
        private $_sides = array();
        private $_perimeter = NULL;
        function __construct($s0 = 0, $s1 = 0, $s2 = 0) {
            $this->_sides[] = $s0;
            $this->_sides[] = $s1;
            $this->_sides[] = $s2;

            // Tính toán và thiết lập chu vi hình tam giác
            $this->_perimeter = array_sum($this->_sides);
        }
        // Phương thức tính diện tích hình tam giác từ chu vi và các cạnh
        public function getArea() {
            return (SQRT(($this->_perimeter/2) * (($this->_perimeter/2) - $this->_sides[0]) * (($this->_perimeter/2) - $this->_sides[1]) * (($this->_perimeter/2) - $this->_sides[2])));
        }
        // Phương thức lấy chu vi hình tam giác
        public function getPerimeter() {
            return $this->_perimeter;
        }
    }

    /* Định nghĩa class Rectangle
    * Các thuộc tính của class: width(chiều rộng), height(chiều cao).
    * Các phương thức của lớp:
    * - setSize()
    * - getArea()
    * - getPerimeter()
    * - isSquare()
    */
    class Rectangle {
        // Khai báo các thuộc tính
        public $width = 0;
        public $height = 0;

        // Hàm khởi tạo
        function __construct($w = 0, $h = 0) {
           $this->width = $w;
           $this->height = $h;
        }

        // Phương thức này thiết lập các kích thước của hình chữ nhật
        function setSize($w = 0, $h = 0) {
            $this->width = $w;
            $this->height = $h;
        }

        // Phương thức này tính diện tích hình chữ nhật
        function getArea() {
            return ($this->width * $this->height);
        }

        // Phương thức này tính chu vi hình chữ nhật
        function getPerimeter() {
            return ( ($this->width + $this->height) * 2 );
        }

        // Phương thức này kiểm tra xem hình chữ nhật này có phải là hình vuông
        function isSquare() {
            if ($this->width == $this->height) {
                return true; // Hình chữ nhật
            } else {
                return false; // Không phải hình chữ nhật
            }
        }
    }
    #------------ KẾT THÚC ĐỊNH NGHĨA CLASS ----------------------#

    if (isset($_GET['shape'], $_GET['dimensions'])) {
        // Tạo ra một đối tượng từ với thông số từ query string
        $obj = ShapeFactory::Create($_GET['s'], $_GET['d']);

        echo "<h2>Tạo ra hình {$_GET['shape']}:</h2>";
        echo '<p>Diện tích hình: ' . $obj->getArea() . '</p>';
        echo '<p>Chu vi hình: ' . $obj->getPerimeter() . '</p>';
    } else {
        echo '<p>Cần cung cấp hình dạng và kích thước!</p>';
    }

    // Xóa đối tượng
    unset($obj);
    ?>
</body>
</html>

Trong ví dụ này chúng ta đã tạo ra lớp ShapeFactory áp dụng Factory Pattern, nó sẽ nhận các tham số đầu vào để tạo ra một thực thể tương ứng với class cần tạo. Tiếp đó là các class Rectangle (hình chữ nhật) và Triangle (hình tam giác) được mở rộng từ lớp trìu tượng Shape (hình). Tiếp đó, chúng ta sử dụng các query string của URL để đưa vào dạng hình và kích thước hình cần tạo:

  • s – shape là hình cần tạo: rectangle hoặc triangle
  • d – dimension là kích thước của hình, nếu là tam giác nhập 3 cạnh, nếu là hình chữ nhật nhập 2 cạnh.

    Thực hiện chạy thử http://oop.dev/factory.php?s=rectangle&d[\]=10&d[\]=20 chúng ta được kết quả:

Ví dụ 1 về Factory pattern

Tiếp theo thử tạo hình tam giác với các cạnh là 5, 10, 15 với URL http://oop.dev/factory.php?s=triangle&d[\]=5&d[\]=10&d[\]=15 kết quả như sau:

Ví dụ 2 về Factory Pattern

Như vậy với việc áp dụng Factory Pattern chúng ta đã tạo được các đối tượng khác nhau tùy thuộc vào từng tình huống mà không biết trước được như Singleton Pattern.

3. Lời kết

Factory Pattern rất hữu dụng trong việc tạo ra các đối tượng động, ứng dụng sẽ mềm dẻo hơn với việc áp dụng Factory Pattern. Để sử dụng các Design Pattern hiệu quả bạn nên tìm hiểu tất cả các mẫu lập trình trong Create Design Pattern để tìm được pattern phù hợp nhất cho việc tạo đối tượng.


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è.

Singleton Pattern tạo thực thể hiệu quả

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

3 Bình luận trong "Factory Pattern nhà máy tạo thực thể"

  1. Cường $

    5 years ago

    Phản hồi
    Hình như công thức tính diện tích trong ví dụ factory bị sai, chu vi thì tính ra được mà diện tích lại bằng 0???
  2. azup

    5 years ago

    Phản hồi
    công thức tính diện tích hình tam giác dựa vào chu vi như vậy là đúng đấy, tham khảo http://keisan.casio.com/exec/system/1223267646. Diện tích ra bằng 0 do tam giác trong bài này đặc biệt quá, một cạnh bằng tổng hai cạnh, tức tam giác này là một đoạn thẳng do đó diện tích = 0
    1. Minh Nguyen

      5 years ago

      Phản hồi
      "Tam giác hay hình tam giác là một loại hình cơ bản trong hình học: hình hai chiều phẳng có ba đỉnh là ba điểm không thẳng hàng và ba cạnh là ba đoạn thẳng nối các đỉnh với nhau. Tam giác là đa giác có số cạnh ít nhất (3 cạnh là ít nhất). Tam giác luôn luôn là một đa giác đơn, đa giác lồi (các góc trong luôn nhỏ hơn 180o)" => Tam giác có 3 đỉnh không thẳng hàng mà. https://vi.wikipedia.org/wiki/Tam_gi%C3%A1c

Thêm bình luận