1. Nguyên lý Low Coupling là gì?
-
Coupling là thước đo mức độ phụ thuộc của một lớp vào các lớp khác. Khớp nối cao dẫn đến mã khó thay đổi hoặc duy trì một mã duy nhất để thay đổi thành chỉ một mã class có thể dẫn đến những thay đổi lan tỏa khắp hệ thống.
-
Low Coupling là một nguyên tắc thiết kế phần mềm quan trọng, nhằm giảm thiểu sự phụ thuộc lẫn nhau giữa các module hoặc lớp trong một hệ thống. Mục tiêu của Low coupling là để tạo ra một hệthống mà trong đó các phần tử riêng lẻ có thể thay đổi mà không ảnh hưởng đến các phần tử khác.
-
Hãy xem xét ví dụ sau:
Hệ thống gửi tin nhắn có hai loại là SMS và Email:- SMS: Gửi tin nhắn qua điện thoại.
- Email: Gửi email đến người dùng.
-
Cần thiết kế sao cho hệ thống dễ mở rộng (thêm các loại tin nhắn khác) và đạt Low Coupling.
-
Dưới đây là triển khai code bằng ngôn ngữ lập trình Java với High Coupling:
// Lớp gửi SMS
class SMSMessage {
public void sendSMS(String recipient, String content) {
System.out.println("Sending SMS to " + recipient + ": " + content);
}
}
// Lớp gửi Email
class EmailMessage {
public void sendEmail(String recipient, String content) {
System.out.println("Sending Email to " + recipient + ": " + content);
}
}
// Lớp MessageService
class MessageService {
private SMSMessage smsMessage = new SMSMessage();
private EmailMessage emailMessage = new EmailMessage();
public void sendSMS(String recipient, String content) {
smsMessage.sendSMS(recipient, content);
}
public void sendEmail(String recipient, String content) {
emailMessage.sendEmail(recipient, content);
}
}
// Main sử dụng MessageService
public class Main {
public static void main(String[] args) {
MessageService service = new MessageService();
// Gửi SMS
service.sendSMS("1234567890", "Hello via SMS!");
// Gửi Email
service.sendEmail("user@example.com", "Hello via Email!");
}
}
-
Giải thích đoạn code trên:
- Class
SMSMessage
thực hiện gửi tin nhắn thông SMS. - Class
EmailMessage
thực hiện gửi tin nhắn thông qua Email. - Class
MessageService
thực hiện tạo các đối tượng từSMSMessage
,EmailMessage
và tạo 2 phương thức gửi Message tương ứng. - Class
Main
chứa phương thức main thực hiện tạo đối tượng từMessageService
và thực hiện 2 phương thức gửiMessage
.
- Class
-
Dễ thấy vấn đề gặp phải với High Coupling:
- Sự phụ thuộc cao:
- MessageService phụ thuộc trực tiếp vào các lớp
SMSMessage
vàEmailMessage
. - Nếu thêm loại tin nhắn mới (ví dụ: Push Notification), phải sửa đổi
MessageService
. - Khó mở rộng: Khi thêm loại tin nhắn, phải thay đổi mã nguồn của MessageService, vi phạm nguyên tắc Open/Closed.
- Khó kiểm thử: Không thể kiểm thử MessageService độc lập mà không cần đến các lớp
SMSMessage
hoặcEmailMessage
. - Không linh hoạt:
MessageService
bị ràng buộc chặt chẽ với cách triển khai của từng loại tin nhắn.
-
Cách giải quyết:
- Dependency Injection: Các module không giao tiếp trực tiếp với nhau, mà thông qua interface. Module cấp thấp sẽ implement interface, module cấp cao sẽ gọi module cấp thấp thông qua interface. Dưới đây là code sau khi áp dụng Dependency Injection:
// Interface chung cho các loại Message
interface Message {
void send(String recipient, String content);
}
// Lớp thực hiện gửi SMS
class SMSMessage implements Message {
@Override
public void send(String recipient, String content) {
System.out.println("Sending SMS to " + recipient + ": " + content);
}
}
// Lớp thực hiện gửi Email
class EmailMessage implements Message {
@Override
public void send(String recipient, String content) {
System.out.println("Sending Email to " + recipient + ": " + content);
}
}
// Lớp sử dụng Message
class MessageService {
private Message message;
public MessageService(Message message) {
this.message = message;
}
public void sendMessage(String recipient, String content) {
message.send(recipient, content);
}
}
public class Main {
public static void main(String[] args) {
// Gửi SMS
Message sms = new SMSMessage();
MessageService smsService = new MessageService(sms);
smsService.sendMessage("1234567890", "Hello via SMS!");
// Gửi Email
Message email = new EmailMessage();
MessageService emailService = new MessageService(email);
emailService.sendMessage("user@example.com", "Hello via Email!");
}
}
-
Trong đoạn code trên, ta sẽ sử dụng tạo một interface
Message
chứa phương thức trừu tượng làsendMessage
. Hai classSMSMessage
vàEmailMessage
sẽ implements interfaceMessage
vàOverride
lại phương thứcsendMessage
sao cho phù hợp với mục đích của từng class. -
Class
MessageService
sẽ đảm nhận việc thực thi phương thức gửi tin nhắn, nhưng ở đây sẽ không sử dụngSMSMessage
vàEmailMessage
để khởi tạo trực tiếp đối tượng mà sẽ dùng interfaceMessage
là thuộc tính trongMessageService
. Tại sao? Bởi vì interface cho phép chúng ta áp dụng tính đa hình trong OOP. -
Trong Class Main, phương thức Main sẽ lần lượt thực hiện:
- Tạo đối tượng
sms
từ ClassSMSMessage
. - Tạo đối tượng
smsService
từ ClassMessageService
. - Đối tượng
smsService
gọi thực hiện phương thứcsendMessage
. - Tạo đối tượng
email
từ ClassEmailMessage
. - Tạo đối tượng
emailService
từ ClassMessageService
. - Đối tượng
emailService
gọi thực hiện phương thứcsendMessage
.
- Tạo đối tượng
-
Dễ thấy, chúng ta có thể dễ dàng tùy biến loại
Message
mà đối tượng được tạo từMessageService
sẽ thực thi, từ đó dễ dàng thêm các loạiMessage
khác.
2. Lợi ích của nguyên lý Low Coupling
3. Kết luận: