Nội dung
Mục tiêu
Prototype là một mẫu thiết kế khởi tạo cho phép bạn sao chép các đối tượng hiện có mà không làm cho mã của bạn phụ thuộc vào các lớp của chúng.
Đặt vấn đề
Giả sử bạn có một đối tượng và bạn muốn tạo một bản sao chính xác của nó. Bạn sẽ làm điều này như thế nào? Đầu tiên, bạn phải tạo một đối tượng mới của cùng một lớp. Sau đó, bạn phải duyệt qua tất cả các trường của đối tượng ban đầu và sao chép giá trị của chúng sang đối tượng mới.
Đẹp! Nhưng có một rắc rối. Không phải tất cả các đối tượng đều có thể được sao chép theo cách đó vì một số trường của đối tượng có thể là riêng tư (private) và không thể nhìn thấy từ bên ngoài đối tượng.
Còn một vấn đề nữa với cách tiếp cận trực tiếp. Vì bạn phải biết lớp của đối tượng để tạo bản sao, mã của bạn sẽ phụ thuộc vào lớp đó. Nếu sự phụ thuộc thêm không khiến bạn sợ hãi, thì có một cách khác. Đôi khi bạn chỉ biết giao diện mà đối tượng tuân theo, nhưng không biết lớp cụ thể của nó, ví dụ, một tham số trong một phương thức có thể chấp nhận bất kỳ đối tượng nào mà tuân theo giao diện đó.
Giải pháp
Mẫu Prototype ủy thác quá trình nhân bản cho các đối tượng thực tế đang được nhân bản. Mẫu khai báo một giao diện chung cho tất cả các đối tượng hỗ trợ nhân bản. Giao diện này cho phép bạn sao chép một đối tượng mà không cần ghép mã của bạn với lớp của đối tượng đó. Thông thường, một giao diện như vậy chỉ chứa một phương thức sao chép duy nhất là clone
.
Việc triển khai phương thức clone là tương tự nhau trong tất cả các lớp. Phương thức này tạo một đối tượng của lớp hiện tại và chuyển tất cả các giá trị của các trường ở đối tượng cũ sang một đối tượng mới. Bạn thậm chí có thể sao chép các trường riêng tư vì hầu hết các ngôn ngữ lập trình đều cho phép các đối tượng truy cập các trường riêng tư của các đối tượng khác thuộc cùng một lớp.
Đây là cách nó hoạt động: bạn tạo một tập hợp các đối tượng, được cấu hình theo nhiều cách khác nhau. Khi cần một đối tượng giống như đối tượng đã cấu hình, bạn chỉ cần sao chép một prototype thay vì xây dựng một đối tượng mới từ đầu.
Cấu trúc
- Giao diện Prototype khai báo các phương thức nhân bản. Trong hầu hết các trường hợp, đó là một hàm
clone
. - Lớp Concrete Prototype thực hiện phương thức nhân bản. Ngoài việc sao chép dữ liệu của đối tượng gốc sang bản sao, phương pháp này cũng có thể xử lý một số trường hợp đặc biệt của quá trình sao chép liên quan đến việc sao chép các đối tượng được liên kết, gỡ rối các phụ thuộc đệ quy, v.v.
- Client có thể tạo một bản sao của bất kỳ đối tượng nào tuân theo giao diện Prototype.
Triển khai đăng ký Prototype
Prototype Registry cung cấp một cách dễ dàng để truy cập các prototype được sử dụng thường xuyên. Nó lưu trữ một tập hợp các đối tượng được tạo sẵn sẵn sàng được sao chép. Prototype Registry đơn giản nhất là bảng băm name → prototype. Tuy nhiên, nếu bạn cần tiêu chí tìm kiếm tốt hơn một name đơn giản, bạn có thể xây dựng một kiểu mạnh mẽ hơn.
Khả năng áp dụng
- Sử dụng mẫu Prototype khi mã của bạn không phụ thuộc vào các lớp cụ thể của đối tượng mà bạn cần sao chép.
- Sử dụng khi bạn muốn giảm số lượng lớp con chỉ khác nhau về cách chúng khởi tạo các đối tượng tương ứng.
Ưu và nhược điểm
😄😄😄
Sao chép các đối tượng mà không cần ghép nối với các lớp cụ thể của chúng.
Loại bỏ việc khởi tạo lặp đi lặp lại có lợi cho việc nhân bản các prototype được tạo sẵn.
Tạo các đối tượng phức tạp một cách thuận tiện hơn.
Một giải pháp thay thế cho kế thừa khi xử lý trước các cài đặt cấu hình cho các đối tượng phức tạp.
🙁🙁🙁
Sao chép các đối tượng phức tạp có tham chiếu vòng có thể rất khó.
Mối quan hệ với các mẫu khác
- Nhiều thiết kế bắt đầu bằng cách sử dụng Factory Method (ít phức tạp hơn và có thể tùy chỉnh nhiều hơn thông qua các lớp con) và phát triển theo hướng Abstract Factory, Prototype hoặc Builder (linh hoạt hơn nhưng phức tạp hơn).
- Các Abstract Factory thường dựa trên một tập các phương thức factory, nhưng bạn cũng có thể sử dụng Prototype để soạn các phương thức trên các lớp này.
- Prototype có thể hữu ích khi bạn cần lưu các bản sao của Commands vào lịch sử.
- Các thiết kế sử dụng nhiều Composite và Decorator thường có thể được hưởng lợi từ việc sử dụng Prototype. Áp dụng mẫu cho phép bạn sao chép các cấu trúc phức tạp thay vì xây dựng lại chúng từ đầu.
- Prototype không dựa trên tính kế thừa, vì vậy nó không có nhược điểm. Mặt khác, Prototype yêu cầu khởi tạo phức tạp cho đối tượng được nhân bản. Factory Method dựa trên sự kế thừa nhưng không yêu cầu bước khởi tạo.
- Đôi khi Prototype có thể là một sự thay thế đơn giản hơn cho Memento. Điều này hoạt động nếu đối tượng, trạng thái mà bạn muốn lưu trữ trong lịch sử, khá đơn giản và không có liên kết đến tài nguyên bên ngoài hoặc các liên kết dễ thiết lập lại.
- Abstract Factory, Builder and Prototype đều có thể được triển khai dưới dạng các Singleton.
Chương trình tham khảo
C++ Design Patterns: Prototype
Để lại một bình luận