Prototype design pattern allows you to create objects by cloning an existing object instead of creating a new object from scratch. This pattern is used when the process of object creation is costly. When cloning, the newly copied object contains the same characteristics as its source object. After cloning, we can change the values of the new object’s properties as required. This pattern comes under a creational pattern.
Summary
Sử dụng prototype pattern khi:
- Chi phí để tạo mới một object quá lớn.
- Chúng ta nhận object từ một bên thứ ba thông qua interface nào đó, đồng thời chúng ta không biết thông tin của các concrete class. Và chúng ta muốn code của mình không phụ thuộc vào bên thứ ba.
- Có quá nhiều class kế thừa phức tạp mà chỉ khác nhau bởi cách chúng khởi tạo và cấu hình.
Problem
Giả sử chúng ta có một đối tượng và chúng ta muốn có một bản sao y hệt của đối tượng đó. Để sao chép, trước tiên ta cần tạo ra một đối tượng mới có cùng class với đối tượng đó. Sau đó, chúng ta cần duyệt qua tất cả các thuộc tính của đối tượng nguồn để sao chép sang đối tượng mới.
Cách làm này không sai. Tuy nhiên, không phải lúc nào các thuộc tính cũng có thể truy cập nên việc sao chép không phải lúc nào cũng khả thi.
Ngoài ra, cách làm trên có một nhược điểm: do chúng ta cần phải tạo ra một đối tượng mới có cùng class với đối tượng nguồn, code của chúng ta trở nên phụ thuộc vào class đó.
Solution
Giải pháp cho vấn đề này là ta sẽ xây dựng phương thức clone
dùng để tạo ra đối tượng mới dựa trên đối tượng nguồn. Đối tượng mà hỗ trợ clone thì được gọi là prototype.
Trong trường hợp object có hàng tá thuộc tính và hàng trăm cách cấu hình thì việc cloning sẽ đơn giản hơn là subclassing (chia thành các lớp con).
Ý tưởng của prototype pattern là: tạo ra một danh sách các đối tượng được cấu hình sẵn. Khi cần sử dụng một đối tượng tương tự như một trong số những đối tượng đã được cấu hình, ta chỉ cần clone một prototype thay vì xây dựng một đối tượng mới từ ban đầu.
Structure
Có hai cấu trúc của prototype pattern:
Basic
Cấu trúc cơ bản sẽ bao gồm những thành phần sau:
- Prototype: là một interface định nghĩa phương thức
clone
. - Concrete prototype: cài đặt phương thức
clone
. - Client: tạo ra bản sao của một đối tượng mà tuân theo prototype interface.
Registry
Cấu trúc registry có thêm một prototype registry: là một class có chứa một danh sách các prototype thường dùng. Danh sách này thường là một hash map.
Implementation
Giả sử ta có một nhà máy sản xuất máy tính với hai prototype là gaming và working computer. Chúng ta cần áp dụng prototype pattern để có thể sản xuất hàng loạt nhiều máy tính từ hai prototype đó.
Computer Types
Trước tiên ta tạo ra enum cho các kiểu máy tính như sau:
Prototype
Xây dựng prototype:
Ngoài phương thức clone
, BaseComputer
còn có thêm những phương thức nền cho các concrete prototype chẳng hạn như constructor, getter và setter.
Concrete Prototype
Xây dựng prototype cho gaming và working computer:
Có thể thấy, chúng ta sử dụng copy constructor (xem thêm Constructor) để tạo ra một đối tượng mới dựa trên đối tượng đã có. Phương thức clone
chỉ đơn giản là gọi copy constructor và truyền vào đối tượng hiện tại.
Prototype Registry
Xây dựng một class có factory method giúp quản lý các prototype thường dùng:
Usage
Gọi sử dụng như sau:
Output:
Applicability
Sử dụng prototype pattern khi:
- Ta không muốn phụ thuộc vào các concrete class của đối tượng mà ta muốn sao chép.
- Giảm số lượng các class con mà chỉ khác nhau cách khởi tạo.
Pros and Cons
Pros | Cons |
---|---|
Có thể sao chép đối tượng mà không phụ thuộc vào concrete class của đối tượng đó | Cloning các đối tượng có tham chiếu vòng có thể khó khăn |
Giảm bớt các đoạn code khởi tạo khi sao chép các prototype có sẵn | |
Tạo ra các đối tượng phức tạp dễ dàng hơn |