💡 Vì sao cần sử dùng Dependency Injection(DI)?
Trong lập trình hướng đối tượng, một vấn đề rất phổ biến mà các developer thường gặp phải đó là tight-coupling – các class phụ thuộc chặt chẽ vào nhau. Điều này khiến cho việc bảo trì, mở rộng hoặc thay đổi logic trở nên khó khăn. Để giải quyết vấn đề này, chúng ta có thể sử dụng một kỹ thuật gọi là Dependency Injection (DI).
Giả sử bạn đang xây dựng một ứng dụng Java nhỏ, nơi bạn muốn gửi tin nhắn thông qua email hoặc SMS. Hãy cùng xem ví dụ đơn giản dưới đây.
🧪 Ví dụ ban đầu: Không dùng DI
-
Tạo class
EmailService
package service; public class EmailService { public void sendMessage(String message) { System.out.println("Email sent: " + message); } }
-
Sử dụng
EmailService
trong classClient
import service.EmailService; public class Client { private EmailService emailService = new EmailService(); public void processMessage(String msg) { emailService.sendMessage(msg); } }
-
Gọi class
Client
từMain
public class Main { public static void main(String[] args) { Client client = new Client(); client.processMessage("Dev java rat nhieu tien"); } }
Kết quả:
Email sent: Dev java rat nhieu tien
⚠️ Vấn đề phát sinh khi mở rộng
Giả sử bây giờ bạn muốn thêm một kênh gửi tin nhắn khác là SMS. Bạn tạo thêm class SMSService
như sau:
package service; public class SMSService { public void sendMessage(String message) { System.out.println("SMS sent: " + message); }
}
Sau đó, bạn sửa Client
để dùng SMSService
thay vì EmailService
:
import service.SMSService; public class Client { private SMSService smsService = new SMSService(); public void processMessage(String msg) { smsService.sendMessage(msg); }
}
Chạy chương trình sẽ ra như thế này: SMS sent: Dev java rat nhieu tien
⚠️ Nhận xét:
-
Client
đang phụ thuộc chặt chẽ (tight-coupling) vàoEmailService
hoặcSMSService
-
Việc thay đổi từ email sang SMS yêu cầu sửa trực tiếp mã nguồn, điều này vi phạm nguyên tắc đóng-mở trong lập trình hướng đối tượng (Open/Closed Principle).
-
Giải pháp là giảm sự phụ thuộc, hay còn gọi là loose-coupling — và đó là lúc Dependency Injection (DI) phát huy tác dụng.
✅ Dependency Injection là gì?
Dependency Injection (DI) là một design pattern giúp tách rời việc khởi tạo đối tượng ra khỏi lớp sử dụng nó.
Thay vì để Client tự tạo ra EmailService hay SMSService, ta sẽ truyền đối tượng này từ bên ngoài (inject).
Các cách triển khai DI:
- Constructor Injection ✅ (phổ biến nhất)
- Setter Injection
- Interface Injection
🔁 Refactor ví dụ trên dùng DI
-
Tạo interface
MessageService
package service; public interface MessageService { void sendMessage(String message); }
-
Sửa
EmailService
vàSMSService
để implementMessageService
package service; public class EmailService implements MessageService { public void sendMessage(String message) { System.out.println("Email sent: " + message); } }
package service; public class SMSService implements MessageService { public void sendMessage(String message) { System.out.println("SMS sent: " + message); } }
-
Bước quan trọng nhất, "tiêm"
MessageService
vàoClient
bằng hàm constructorimport service.MessageService; public class Client { private MessageService messageService; public Client(MessageService messageService) { this.messageService = messageService; } public void processMessage(String msg) { messageService.sendMessage(msg); } }
-
Cuối cùng là chỉnh sửa
Main
với nhiều loại serviceimport service.EmailService; import service.MessageService; import service.SMSService; public class Main { public static void main(String[] args) { MessageService emailService = new EmailService(); MessageService smsService = new SMSService(); Client emailClient = new Client(emailService); emailClient.processMessage("Email client"); Client smsClient = new Client(smsService); smsClient.processMessage("SMS client"); } }
Kết quả
Email sent: Email client SMS sent: SMS client
🎯 Tổng kết
Trước DI | Sau khi dùng DI |
---|---|
Tight coupling | Loose coupling |
Khó mở rộng, khó test | Dễ mở rộng, dễ test (mock service) |
Code ít linh hoạt | Code linh hoạt, dễ cấu hình |
Việc sử dụng Dependency Injection không chỉ giúp code dễ bảo trì hơn mà còn là tiền đề để áp dụng các framework hiện đại như Spring, nơi DI được tích hợp sâu và tự động hóa.
✅ Hãy nhớ: càng ít phụ thuộc chặt chẽ, ứng dụng của bạn càng dễ thích nghi với sự thay đổi!
Tóm lại, Dependency Injection là một kỹ thuật đơn giản nhưng cực kỳ hiệu quả để giúp mã nguồn trở nên linh hoạt, dễ mở rộng và bảo trì hơn. Nếu bạn muốn xây dựng các ứng dụng hiện đại và dễ quản lý, DI chắc chắn là một kiến thức không thể bỏ qua.