Nội dung
Mục tiêu
Composite là một mẫu thiết kế cấu trúc cho phép bạn bố cục các đối tượng thành cấu trúc cây và sau đó làm việc với các cấu trúc này như thể chúng là các đối tượng riêng lẻ.
Vấn đề
Sử dụng mẫu Composite chỉ có ý nghĩa khi mô hình cốt lõi của ứng dụng của bạn có thể được biểu diễn dưới dạng cây.
Ví dụ, tưởng tượng rằng bạn có hai loại đối tượng: Product
và Box
. Một Box
có thể chứa một số Product
cũng như một số Box
nhỏ hơn. Những Box
nhỏ này cũng có thể chứa một số Product
hoặc thậm chí là Box
nhỏ hơn, v.v.
Giả sử bạn quyết định tạo một hệ thống đặt hàng sử dụng các lớp này. Đơn hàng có thể chứa các sản phẩm đơn giản mà không có bất kỳ bao bì nào, cũng như các hộp chứa sản phẩm và các hộp khác. Bạn sẽ xác định tổng giá của một đơn hàng như thế nào?
Bạn có thể thử cách tiếp cận trực tiếp, mở tất cả các hộp, xem qua tất cả các sản phẩm và tính tổng. Điều đó có thể làm được trong thế giới thực; nhưng trong một chương trình, nó không đơn giản như chạy một vòng lặp. Bạn phải biết trước các loại Product
và Box
, cấp độ lồng vào nhau của các Box
và các chi tiết khó chịu khác. Tất cả những điều này làm cho cách tiếp cận trực tiếp trở nên quá khó khăn hoặc thậm chí là không thể.
Giải pháp
Mẫu Composite đề xuất làm việc với sản phẩm (Product)
và Hộp (Box
) thông qua giao diện chung khai báo phương pháp tính tổng giá.
Phương pháp này sẽ hoạt động như thế nào? Đối với một sản phẩm, nó chỉ cần trả lại giá của sản phẩm. Đối với một hộp, nó sẽ xem xét từng mục trong hộp, hỏi giá của nó và sau đó trả lại tổng số cho hộp này. Nếu một trong những mặt hàng này là một hộp nhỏ hơn, hộp đó cũng sẽ bắt đầu xem xét nội dung của nó, v.v., cho đến khi tính được giá của tất cả các thành phần bên trong. Một hộp thậm chí có thể thêm một số chi phí bổ sung vào giá cuối cùng, chẳng hạn như chi phí đóng gói.
Lợi ích lớn nhất của phương pháp này là bạn không cần quan tâm đến các lớp cụ thể của các đối tượng tạo nên cây. Bạn không cần biết một đối tượng là một sản phẩm đơn giản hay một chiếc hộp phức tạp. Bạn có thể xử lý tất cả chúng như nhau thông qua giao diện chung. Khi bạn gọi một phương thức, các đối tượng tự chuyển yêu cầu xuống cây.
Cấu trúc
- Giao diện Component mô tả các hoạt động phổ biến cho các phần tử đơn giản và phức tạp của cây.
- Leaf là phần tử cơ bản của cây không có phần tử phụ. Thông thường, các thành phần này thực hiện hầu hết các công việc thực sự, vì chúng không có bất kỳ ai để ủy quyền công việc.
- Container (hay còn gọi là composite) là một phần tử có các phần tử phụ: leaf hoặc các container khác. Một container không biết các lớp cụ thể của con của nó. Nó chỉ hoạt động với tất cả các phần tử con thông qua giao diện Component.
Khi nhận được yêu cầu, container ủy quyền công việc cho các phần tử con của nó, xử lý các kết quả trung gian và sau đó trả lại kết quả cuối cùng cho client. - Client làm việc với tất cả các phần tử thông qua giao diện Component. Do đó, client có thể làm việc theo cùng một cách với cả các phần tử đơn giản hoặc phức tạp của cây.
Khả năng áp dụng
- Sử dụng mẫu Composite khi bạn phải triển khai cấu trúc đối tượng dạng cây.
- Sử dụng mẫu khi bạn muốn client xử lý đồng nhất cả phần tử đơn giản và phức tạp.
Ưu và nhược điểm
😄😄😄
Có thể làm việc với các cấu trúc cây phức tạp thuận tiện hơn: sử dụng đa hình và đệ quy.
Nguyên tắc Mở / Đóng: Có thể giới thiệu các loại phần tử mới vào ứng dụng mà không cần phá vỡ mã hiện có, mã này hiện hoạt động với cây đối tượng.
🙁🙁🙁
Có thể khó cung cấp một giao diện chung cho các lớp có chức năng khác nhau quá nhiều. Trong một số trường hợp nhất định, cần phải tổng quát hóa quá mức giao diện thành phần, khiến nó khó hiểu hơn.
Mối quan hệ với các mẫu khác
- Có thể sử dụng Builder khi tạo các cây Composite phức tạp vì có thể lập trình các bước xây dựng của nó để hoạt động một cách đệ quy.
- Chain of Responsibility thường được sử dụng cùng với Composite. Trong trường hợp này, khi một leaf nhận được một yêu cầu, có thể truyền nó qua chuỗi của tất cả các thành phần cha tới root của cây đối tượng.
- Có thể sử dụng Iterators để duyệt qua cây Composite.
- Có thể sử dụng Visitor để thực hiện một hoạt động trên toàn bộ cây Composite.
- Có thể triển khai chia sẻ các nút leaf của cây Composite dưới dạng Flyweights để tiết kiệm RAM.
- Composite và Decorator có sơ đồ cấu trúc tương tự nhau vì cả hai đều dựa vào thành phần đệ quy để tổ chức một số lượng đối tượng kết thúc mở.
Decorator giống như Composite nhưng chỉ có một thành phần con. Có một sự khác biệt đáng kể khác: Decorator bổ sung thêm các trách nhiệm cho đối tượng được bao bọc, trong khi Composite chỉ “tổng hợp” các kết quả con của nó.
Tuy nhiên, các mẫu cũng có thể hợp tác nhau: có thể sử dụng Decorator để mở rộng hành vi của một đối tượng cụ thể trong cây Composite. - 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.
Để lại một bình luận