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

PROTOTYPE PATTERN LÀ GÌ VÀ CÁCH SỬ DỤNG NÓ TRONG PHP

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

Prototype Pattern là gì thế?

Prototype Pattern là một loại design pattern thuộc nhóm khởi tạo (creational patterns). Về bản chất, loại design pattern này cung cấp cơ chế cho phép khởi tạo một đối tượng bằng cách sao chép từ một đối tượng khác đã tồn tại thay vì sử dụng toán tử new. Đối tượng mới là một bản sao có thể giống hoàn toàn hoặc đã được thay đổi một số thuộc tính so với đối tượng gốc, chúng ta có thể thoải mái thay đổi dữ liệu của đối tượng bản sao này mà không làm ảnh hưởng đến đối tượng gốc kia. Prototype Pattern được sử dụng khi bạn không muốn tốn nhiều chi phí và thời gian cho việc tạo ra một đối tượng mới hoàn toàn trong khi bạn đã có sẵn một đối tượng khác tương tự tồn tại.

Prototype Pattern là một loại design pattern thuộc nhóm khởi tạo

Cấu trúc

Prototype Pattern bao gồm ba thành phần cơ bản là: Prototype, Concrete Prototype và Client.

Cấu trúc của Prototype Pattern

Trong đó:

  • Prototype: Là một class, interface hoặc abstract class trong đó có chứa phương thức clone().
  • Concrete Prototype: Các lớp này có nhiệm vụ thực thi interface (hoặc kế thừa từ class) Prototype để định nghĩa phương thức copy của chính bản thân nó. Chúng ta hoàn toàn có thể bỏ qua lớp này nếu Prototype là một class và đã định nghĩa phương thức clone() của chính nó.
  • Client: Là nơi khởi tạo đối tượng bằng cách gọi tới Concrete Prototype tương ứng để thực hiện việc clone chính nó.

Khi nào nên sử dụng Prototype Pattern?

Dưới đây là một số trường hợp chúng ta có thể cân nhắc sử dụng Prototype Pattern:

  • Chúng ta muốn hạn chế phân lớp và giảm số lượng các lớp con cho việc khởi tạo đối tượng.
  • Chúng ta muốn truyền một đối tượng nào đó vào một hàm để xử lý, thay vì truyền thẳng đối tượng gốc (có thể ảnh hưởng dữ liệu) thì chúng ta có thể truyền vào đối tượng sao chép của nó.
  • Chi phí của việc tạo ra đối tượng mới bằng cách sử dụng toán tử new là khá lớn.

clone và __clone() trong PHP

PHP có cung cấp từ khóa clone cho phép nhân bản một đối tượng có sẵn mà không cần phải khởi tạo đối tượng mới.

Cú pháp:

$object2 = clone $object1;

Bên cạnh từ khóa clone, PHP còn cung cấp __clone() magic method. Ngay sau khi đối tượng được nhân bản hoàn chỉnh thì phương thức __clone() của đối tượng mới được tạo này sẽ được gọi tới.

Ví dụ:

<?php
class Person {
    public $name = "John Smith";
    public $age = 21;
    public $occupation = "Software Developer";

    public function __clone() {
        echo "__clone() is invoked!";
    }
}

$person1 = new Person();
$person2 = clone $person1;
echo $person2->name . " is " . $person2->age . " years old and he is a " . $person2->occupation;
?>

Kết quả thu được:

__clone() is invoked!
John Smith is 21 years old and he is a Software Developer;

Ví dụ minh họa về Prototype Pattern

<?php
abstract class BookPrototype {
    protected $title;
    protected $topic;

    abstract function __clone();

    function getTitle() {
        return $this->title;
    }

    function setTitle($titleIn) {
        $this->title = $titleIn;
    }

    function getTopic() {
        return $this->topic;
    }
}

class PHPBookPrototype extends BookPrototype {
    function __construct() {
        $this->topic = "PHP";
    }

    function __clone() {
    }
}

class SQLBookPrototype extends BookPrototype {
    function __construct() {
        $this->topic = "SQL";
    }

    function __clone() {
    }
}

class HTMLBookPrototype extends BookPrototype {
    function __construct() {
        $this->topic = "HTML";
    }

    function __clone() {
    }
}
// Client
echo "BEGIN TESTING PROTOTYPE PATTERN\n\n";

$phpProto = new PHPBookPrototype();
$sqlProto = new SQLBookPrototype();
$htmlProto = new HTMLBookPrototype();

$book1 = clone $sqlProto;
$book1->setTitle("SQL for Cats");

echo "Book 1 topic: " . $book1->getTopic() . "\n";
echo "Book 1 title: " . $book1->getTitle() . "\n\n";

$book2 = clone $phpProto;
$book2->setTitle("Learning PHP from Scratch");

echo "Book 2 topic: " . $book2->getTopic() . "\n";
echo "Book 2 title: " . $book2->getTitle() . "\n\n";

$book3 = clone $sqlProto;
$book3->setTitle("Learning SQL from Scratch");

echo "Book 3 topic: " . $book3->getTopic() . "\n";
echo "Book 3 title: " . $book3->getTitle() . "\n\n";

$book4 = clone $htmlProto;
$book4->setTitle("Learning HTML from Scratch");

echo "Book 4 topic: " . $book4->getTopic() . "\n";
echo "Book 4 title: " . $book4->getTitle() . "\n\n";

echo "END TESTING PROTOTYPE PATTERN";
?>

Kết quả thu được:

BEGIN TESTING PROTOTYPE PATTERN

Book 1 topic: SQL
Book 1 title: SQL For Cats

Book 2 topic: PHP
Book 2 title: Learning PHP from Scratch

Book 3 topic: SQL
Book 3 title: Learning HTML from Scratch

Book 4 topic: HTML
Book 4 title: Learning HTML from Scratch

END TESTING PROTOTYPE PATTERN

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

Ưu điểm

  • Prototype Pattern giúp giảm chi phí, thời gian và góp phần làm tăng hiệu suất của chương trình do không sử dụng toán tử new để tạo ra đối tượng mới.
  • Prototype Pattern giúp giảm độ phức tạp cho việc khởi tạo đối tượng: do mỗi lớp chỉ implement cách clone của chính nó.
  • Với Prototype Pattern, chúng ta có thể hạn chế việc phân lớp và tạo ra nhiều lớp con cho việc khởi tạo đối tượng như của Abstract Factory Pattern.
  • Prototype Pattern giúp tăng tính linh động của hệ thống vì nó cho phép khởi tạo đối tượng mới bằng cách thay đổi một vài thuộc tính của đối tượng gốc được nó sao chép.

Nhược điểm

  • Việc nhân bản các đối tượng phức tạp có tham chiếu vòng có thể gây ra không ít khó khăn.

Kết luận

Trong bài viết này, chúng ta đã cùng nhau tìm hiểu về Prototype Pattern, hy vọng 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, mình sẽ tiếp tục giới thiệu cho các bạn một design pattern mới thuộc nhóm khởi tạo mang tên “Singleton”. Các bạn nhớ đón xem nhé!

Gửi phản hồi