Design Pattern | Composite Pattern

Các tòa nhà bao gồm các phòng, mặc dù các tòa nhà và phòng có chức năng hơi khác nhau. về cơ bản chúng ta coi nó là cấu trúc chung của nhà ở. Bạn đều có thể vào ra khỏi một tòa nhà hoặc một căn phòng, và cả hai đều có thể dùng để lưu trữ đồ đạc. Vì vậy, dù có thiết kế khác nhau, nhưng chúng có thể được xử lý cùng theo một cách thống nhất.

The Composite Pattern đạt được 2 mục tiêu, để soạn các cấu trúc lồng nhau của 1 đối tượng theo một cách thống nhất, các mô hình theo các thiết kế cơ bản này.

Một giao diện là Component đóng vai trò là superclass cho một tập hợp các class để tất cả chúng có thể được xử lý đồng nhất, điều này được thực hiện bằng polymorphism. Tất cả các lớp thực hiện phù hợp với 1 giao diện, một abstract superclass có thể được sử dụng để đặt giao diện vì cả hai đều cho phép polymorphism (đa hình).

Nhưng chúng ta sẽ tập trung vào việc sử dụng interface. Lớp composite được sử dụng để tổng hợp bất kỳ lớp nào implement component interface, lớp composite sẽ cho phép bạn duyệt qua và có khả năng thao tác các đối tượng thành phần mà đối tượng hỗn hợp chứa. Lớp leaf đại diện cho một loại không tổng hợp (non- composite type), nó không bao gồm các thành phần khác, tiếp theo, chúng ta muốn đối phó với non-composite và composite object uniformly.


Bằng cách có lớp leaf và lớp composite thực hiện component interface, chúng ta hợp nhất chúng với 1 loai duy nhất, các lớp composite và lớp leaf hiện được coi là các lớp kiểu con của lớp component. Tùy thuộc vào vấn đề, bạn có thể có lớp leaf và lớp composite khác khi sử dụng Composite Pattern. Nhưng chi có một giao diện thành phần tổng thể, hoặc abstract super class, lưu ý rằng một đối tượng hỗn hợp có thể chứa các đối tượng hỗn hợp khác, vì lớp tổng hợp là một loại thành phần phụ. Đây được gọi là thành phần đệ quy, là tên gọi khác của mẫu thiết kế này (Recursive Composition). Có thể khó khăn và khó hiểu để tưởng tượng mẫu thiết kế này thực sự trông thế nào vì tính chất chu kỳ rõ ràng của lớp tổng hợp. Cách dễ nhất để hình dung nó là bằng cách nghĩ về nó như một cái cây (tree).


Ở cấp độ gốc, chúng ta có đối tượng tổng hợp (component) chính, được tạo thành từ các đối tượng thành phần khác. Ở mỗi cấp độ (level), chúng ta có thể thêm nhiều thành phần bên dưới mỗi đối tượng tổng hợp, như một hỗn hợp khác hoặc một lớp leaf.

Lưu ý rẳng bạn chỉ có thể thêm thành phần vào một đối tượng tổng hợp chứ không phải là một đối tượng lá, điều này có nghĩa là một đối tượng tổng hợp có khả năng phát triển cây (tree), trong khi một đối tương leaf lại kết thúc cây. The Composite Pattern được sử dụng để giải quyết hai vấn đề, làm thế nào chúng ta sử dụng các loại đối tượng riêng lẻ để xây dựng một cấu trúc giống như cây và làm thế nào chúng ta có thể xử lý các loại đối tượng riêng lẻ mà không cần kiểm tra các loại (types) của chúng ?


Trên là sơ đồ UML của một Composite Pattern trông như thế nào và cách diễn giải nó, hãy áp dụng nó vào một ví dụ:

Chúng ta sẽ sử dụng ví dụ ở đầu bài về các tòa nhà được cấu tạo từ cấu trúc nhà ở chung. Cấu trúc này được gọi là Component Interface, nó có thể sử dụng để mô  tả tòa nhà, một căn phòng, một tầng, mặc dù mỗi loại này là những đối tượng khác nhau. Lớp housing là lớp tổng hợp (composite class), nhà ở (housing) là một loại cấu trúc, cũng có thể chứa các cấu trúc khác. Điều này có nghĩa là một đối tượng nhà ở (housing class) có thể chứa các loại nhà ở khác.

Ví dụ, một tòa nhà có thể được implement bởi housing object, và một building có thể chứa các tầng, mỗi tầng được đại diện bởi một nhà ở khác. Chúng ta có thể đi qua tòa nhà từ tầng này sang tầng khác vì tòa nhà này bao gồm các tầng, tất cả đều là vật thể "nhà ở". Còn một căn phòng được gọi là lớp lá (leaf), vì một căn phòng không thể chứa các căn phòng khác.

Vậy là, chúng ta có một sơ đồ UML mô hình hóa cách tòa nhà được tạo ra từ các loại cấu trúc nhà ở và phòng.

Tiếp theo, chúng ta sẽ thực hiện thử Composite Pattern trên JAVA. Bước 1, thiết kế giao diện xác định tổng thể, chúng ta bắt đầu bằng cách định nghĩa giao diện mà các lớp component và leaf sẽ thực hiện, điều này hỗ trợ đa hình (polymorphism) cho component và leaf của bạn.


Bước 2, thực hiện lớp composite, bạn sẽ phải implement interface bên trong composite class, điều này cung cấp cho lớp housing hành vi của chính nó khi client sử dụng code, vì đối tượng housing của chúng ta có thể bao gồm các cấu trúc khác, bạn sẽ cần ngăn chặn thể hiện này bằng một bộ sưu tập phù hợp, bạn sẽ cần một phương thức để thêm nhiều thành phần vào composite object, ở đây, chúng ta đã có danh sách các mảng riêng và chỉ thay đổi nó thông qua phương thức addStructure() công khai.


Để duyệt qua các thành phần của một composite object, bạn có thể sẽ phải truy xuất các thành phần khi đưọc yêu cầu, bao gồm các đối tượng bổ sung sẽ giúp quản lý các component object, tùy thuộc vào bạn..

Bước 3, thực hiện lớp leaf, vì lớp leaf không chứa bất kỳ thành phần nào, chúng ta không cần thêm list (bộ sưu tập ở trên) hoặc bất kỳ phương thức nào để quản lý thêm bớt các list cả, chúng ta chỉ cần implement các phương thức của interface Istructure.


Bây giờ, chúng ta đã hoàn thành việc implement tòa nhà của mình bằng cách sử dụng Composite Pattern, làm thế nào chúng ta sử dụng nó ? Chúng ta chỉ đơn giản là xây dựng cấu trúc xây dựng theo cấu trúc ~. Trong ví dụ này, tòa nhà của chúng ta có một tầng, trong đó có 1 phòng chung và 2 phòng vệ sinh, điều này rõ ràng là rất đơn giản, nhưng nó cho thấy ý tưởng rằng mẫu thiết kế này có thể mạnh đến cỡ nào. Đối tượng composite có thể được xây dựng nhanh chóng và dễ dàng, mỗi thành phần có thể được dự kiến  sẽ có cùng một tập hợp các hành vi mà không cần thực hiện bất kỳ kiểm tra loại nào.



Tóm lại, Composite Pattern được sử dụng để giải quyết vấn đề về cách xây dựng cấu trúc, giống như cây của các đối tượng, và cách sử lý đồng nhất các đối tượng đó, điều này đạt được bằng cách thực thi tính đa hình trên mỗi lớp thông qua việc thực hiện một giao diện hoặc kế thừa từ một siêu lớp. Và sử dụng một kỹ thuật gọi là đệ quy, cho phép các đối tượng được cấu thành từ các đối tượng khác.

Bạn có thể nghĩ về mẫu thiết kế này khi áp dụng các nguyên tắc thiết kế hướng đối tượng phân rã và khái quát hóa để cùng nhau phá vỡ toàn bộ các thành phần, nhưng có các phần đều phù hợp với một loại chung. Composite Pattern cho phép bạn xây dựng các cấu trúc phức tạp bằng đối tương composite và leaf, điều này giúp dễ hiểu và thao tác cấu trúc hơn, dẫn đến mã dễ đọc hơn, có thể sử dụng lại và ý nghĩa hơn.
Cảm ơn.


Nhận xét

Bài đăng phổ biến từ blog này

Hiểu về Norm Regularization

Những thuật toán nền tảng trong lĩnh vực Trí tuệ nhân tạo (Artificial Intelligence I)