Composition trong Java là kỹ thuật thiết kế để triển khai mối quan hệ has-a trong các lớp.
Trong bài viết này, tôi sẽ cùng bạn đi sâu tìm hiểu về Composition, cách nó hoạt động qua các ví dụ cụ thể, và những lợi ích vượt trội mà nó mang lại trong quá trình phát triển ứng dụng Java. H
Composition trong Java
Composition trong java được thực hiện bằng cách sử dụng các biến thể hiện (instance variables) tham chiếu đến các đối tượng khác. Nói cách khác, một lớp “chứa” một đối tượng của lớp khác. Ví dụ điển hình là một Person
(người) has-a
(có một) Job
(công việc).
Ví dụ về Java Composition
Để dễ hình dung hơn, hãy cùng xem xét một ví dụ thực tế về Composition trong Java với các lớp Person
và Job
.
Đầu tiên, chúng ta định nghĩa lớp Job
:
package com.journaldev.composition;
public class Job {
private String role;
private long salary;
private int id;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public long getSalary() {
return salary;
}
public void setSalary(long salary) {
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Tiếp theo, chúng ta xây dựng lớp Person
, sử dụng Composition để thiết lập mối quan hệ ‘has-a’ với Job
:
package com.journaldev.composition;
public class Person {
// composition has-a relationship
private Job job;
public Person(){
this.job = new Job(); // Khởi tạo đối tượng Job
job.setSalary(1000L); // Thiết lập giá trị mặc định cho salary của job
}
public long getSalary() {
// Ủy quyền (delegate) việc lấy lương cho đối tượng job
return job.getSalary();
}
}
Ở đây, bạn sẽ thấy điểm mấu chốt của Composition: Lớp Person
chứa một biến thành viên kiểu Job
(private Job job;
). Điều này thể hiện rõ mối quan hệ ‘Person có một Job’. Trong constructor của Person
, chúng ta khởi tạo đối tượng Job
và đặt mức lương mặc định.
Để kiểm tra cách hoạt động của Composition, chúng ta tạo một lớp TestPerson
:
package com.journaldev.composition;
public class TestPerson {
public static void main(String[] args) {
Person person = new Person();
long salary = person.getSalary();
System.out.println("Salary of the person: " + salary); // In ra 1000
}
}
Lớp TestPerson
minh họa cách chúng ta sử dụng đối tượng Person
và truy cập lương thông qua nó. Như bạn thấy, từ bên ngoài, chúng ta chỉ cần tương tác với đối tượng Person
để lấy thông tin về lương, mà không cần trực tiếp biết về đối tượng Job
bên trong.
Lợi ích của Java Composition
Lưu ý rằng chương trình kiểm thử ở trên về composition trong Java sẽ không bị ảnh hưởng bởi bất kỳ thay đổi nào trong đối tượng Job. Nếu bạn muốn tái sử dụng mã và mối quan hệ giữa hai lớp là has-a thì bạn nên sử dụng composition thay vì inheritance.
Lợi ích của việc dùng composition trong Java là chúng ta có thể kiểm soát phạm vi hiển thị của đối tượng khác đối với các lớp client và chỉ tái sử dụng những gì cần thiết. Ngoài ra, nếu có thay đổi trong phần triển khai của lớp khác, ví dụ như phương thức getSalary
trả về String
, thì chúng ta chỉ cần thay đổi lớp Person để đáp ứng điều đó, còn các lớp client không cần phải chỉnh sửa.
Composition cũng cho phép tạo ra các lớp back-end khi cần, ví dụ, chúng ta có thể thay đổi phương thức getSalary
của Person để khởi tạo đối tượng Job ngay tại thời điểm chạy khi cần thiết.
Kết luận
Tóm lại, Composition trong Java là một công cụ thiết kế hướng đối tượng mạnh mẽ, giúp chúng ta xây dựng mối quan hệ ‘has-a’ giữa các lớp. Chúng ta thực hiện điều này bằng cách nhúng (embedding) các đối tượng của lớp khác làm biến thành viên, sau đó ủy quyền (delegate) các hành vi cần thiết cho chúng.
Trong thực tế, khi bạn thiết kế các hệ thống phức tạp, đặc biệt là trong các kiến trúc Microservices hay các ứng dụng cần sự decoupling cao, Composition sẽ trở thành người bạn đồng hành không thể thiếu. Nó giúp bạn tạo ra các module độc lập, dễ kiểm thử và dễ bảo trì hơn rất nhiều.