Hướng dẫn Java Design Pattern – Composite

Trong các bài viết trước chúng ta đã tìm hiểu về Bridge Pattern và Adapter Pattern. Trong bài viết này chúng ta tiếp tục tìm hiểu một Design Pattern khác thuộc nhóm cấu trúc là Composite Pattern.

1. Composite Pattern là gì?

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Composite là một mẫu thiết kế thuộc nhóm cấu trúc (Structural Pattern). Composite Pattern là một sự tổng hợp những thành phần có quan hệ với nhau để tạo ra thành phần lớn hơn. Nó cho phép thực hiện các tương tác với tất cả đối tượng trong mẫu tương tự nhau.

Composite Pattern được sử dụng khi chúng ta cần xử lý một nhóm đối tượng tương tự theo cách xử lý 1 object. Composite pattern sắp xếp các object theo cấu trúc cây để diễn giải 1 phần cũng như toàn bộ hệ thống phân cấp. Pattern này tạo một lớp chứa nhóm đối tượng của riêng nó. Lớp này cung cấp các cách để sửa đổi nhóm của cùng 1 object. Pattern này cho phép Client có thể viết code giống nhau để tương tác với composite object này, bất kể đó là một đối tượng riêng lẻ hay tập hợp các đối tượng.

Ví dụ: Một chương trình quản lý một hệ thống tập tin với cấu trúc như hình sau:

Một hệ thống tập tin là một cấu trúc cây có chứa các nhánh là các thư mục (folder – composite), cũng như các nút lá là các tệp (file – leaf). Một folder có thể chứa một hoặc nhiều file hoặc folder. Do đó, folder là một đối tượng phức tạp và file là một đối tượng đơn giản. File và Folder có nhiều thao tác và thuộc tính chung, chẳng hạn như: di chuyển (cut) , sao chép (copy), liệt kê (view) hoặc các thuộc tính thư mục như tên tệp và kích thước.

Với cấu trúc như vậy sẽ dễ dàng và thuận tiện hơn để quản lý file và folder thống nhất bằng cách xây dựng một Interface có đầy đủ các phương thức và thuộc tính chung cho cả file và folder.

2. Cài đặt Composite Pattern như thế nào?

Một Composite Pattern bao gồm các thành phần cơ bản sau:

  • Base Component : là một interface hoặc abstract class quy định các method chung cần phải có cho tất cả các thành phần tham gia vào mẫu này.
  • Leaf : là lớp hiện thực (implements) các phương thức của Component. Nó là các object không có con.
  • Composite : lưu trữ tập hợp các Leaf và cài đặt các phương thức của Base Component. Composite cài đặt các phương thức được định nghĩa trong interface Component bằng cách ủy nhiệm cho các thành phần con xử lý.
  • Client: sử dụng Base Component để làm việc với các đối tượng trong Composite.

Ví dụ: Cài đặt Composite Pattern về chương trình quản lý một hệ thống tập tin ở trên.

  • Trước hết chúng ta định nghĩa một Inteface Component (FileComponent) có các phương thức chung cho cả folder và file. Để đơn giản, tôi chỉ tạo 2 phương thức showProperty() và totalSize(). Hai phương thức này sẽ cung cấp thông tin về file và tổng kích thước của nó.
  • Tiếp theo, chúng ta sẽ tạo một class Leaf cài đặt các phương thức của Component (FileLeaf). Một class Composite chứa tập hợp các Leaf và cài đặt các phương thức của Component (FolderComposite).
  • Cuối cùng, chúng ta sẽ tạo một class Client gọi các phương thức của FileComponent và FolderComposite. Cách gọi các phương thức của 2 class này hoàn toàn giống nhau do cùng implement một Component (FileComponent).

FileComponent.java

package com.maixuanviet.patterns.structural.composite;
 
public interface FileComponent {
    void showProperty();
    long totalSize();
}

FileLeaf.java

package com.maixuanviet.patterns.structural.composite;
 
public class FileLeaf implements FileComponent {
 
    private String name;
    private long size;
 
    public FileLeaf(String name, long size) {
        super();
        this.name = name;
        this.size = size;
    }
 
    @Override
    public long totalSize() {
        return size;
    }
 
    @Override
    public void showProperty() {
        System.out.println("FileLeaf [name=" + name + ", size=" + size + "]");
    }
}

FolderComposite.java

package com.maixuanviet.patterns.structural.composite;
 
import java.util.ArrayList;
import java.util.List;
 
public class FolderComposite implements FileComponent {
 
    private List<FileComponent> files = new ArrayList<>();
 
    public FolderComposite(List<FileComponent> files) {
        this.files = files;
    }
 
    @Override
    public void showProperty() {
        for (FileComponent file : files) {
            file.showProperty();
        }
    }
 
    @Override
    public long totalSize() {
        long total = 0;
        for (FileComponent file : files) {
            total += file.totalSize();
        }
        return total;
    }
}

Client.java

package com.maixuanviet.patterns.structural.composite;
 
import java.util.Arrays;
import java.util.List;
 
public class Client {
 
    public static void main(String[] args) {
        FileComponent file1 = new FileLeaf("file 1", 10);
        FileComponent file2 = new FileLeaf("file 2", 5);
        FileComponent file3 = new FileLeaf("file 3", 12);
 
        List<FileComponent> files = Arrays.asList(file1, file2, file3);
        FileComponent folder = new FolderComposite(files);
        folder.showProperty();
        System.out.println("Total Size: " + folder.totalSize());
    }
}

Output của chương trình trên:

FileLeaf [name=file 1, size=10]
FileLeaf [name=file 2, size=5]
FileLeaf [name=file 3, size=12]
Total Size: 27

3. Lợi ích của Composite Pattern là gì?

  • Cung cấp cùng một cách sử dụng đối với từng đối tượng riêng lẻ hoặc nhóm các đối tượng với nhau.

4. Sử dụng Composite Pattern khi nào?

  • Composite Pattern chỉ nên được áp dụng khi nhóm đối tượng phải hoạt động như một đối tượng duy nhất (theo cùng một cách).
  • Composite Pattern có thể được sử dụng để tạo ra một cấu trúc giống như cấu trúc cây.

Related posts:

Hướng dẫn sử dụng luồng vào ra nhị phân trong Java
Mapping Nested Values with Jackson
Java Program to Implement Bubble Sort
Java Program to Generate Random Numbers Using Multiply with Carry Method
Find the Registered Spring Security Filters
Java Program to implement Sparse Vector
Introduction to Project Reactor Bus
Java Program to Print the Kind of Rotation the AVL Tree is Undergoing
Java Program to find the peak element of an array using Binary Search approach
Java Program to Implement ConcurrentHashMap API
Java Program to Implement Graham Scan Algorithm to Find the Convex Hull
Hướng dẫn Java Design Pattern – Iterator
Java Program to Implement Fibonacci Heap
Java Program to Implement Suffix Tree
Creating a Custom Starter with Spring Boot
Send email with JavaMail
TreeSet và sử dụng Comparable, Comparator trong java
Java Program to Implement Brent Cycle Algorithm
Display Auto-Configuration Report in Spring Boot
Java Program to Find Basis and Dimension of a Matrix
Quick Guide to java.lang.System
Làm thế nào tạo instance của một class mà không gọi từ khóa new?
Java Program to Check Whether a Weak Link i.e. Articulation Vertex Exists in a Graph
Java Program to Implement Vector API
Java Program to Implement Quick Sort with Given Complexity Constraint
So sánh HashMap và HashSet trong Java
Java Program to Implement Adjacency Matrix
Guide to UUID in Java
Why String is Immutable in Java?
Java Program to Create the Prufer Code for a Tree
CharSequence vs. String in Java
Java 8 StringJoiner