METHOD INJECTION LÀ GÌ? KHI DỊCH VỤ ĐƯỢC TIÊM TRỰC TIẾP VÀO ĐIỂM RƠI
Sau khi đã đi qua Constructor Injection, Setter Injection và Interface Injection, chúng ta sẽ khép lại bức tranh toàn cảnh về các hình thái tiêm phụ thuộc với mảnh ghép cuối cùng, cũng là hình thái linh hoạt nhất: Method Injection (Tiêm phụ thuộc qua phương thức).
Điều thú vị là nếu bạn đang làm việc với Laravel, rất có thể bạn đang sử dụng Method Injection mỗi ngày mà đôi khi không để ý tên gọi học thuật của nó. Hãy cùng mổ xẻ chi tiết.
1. Bản Chất Của Method Injection Là Gì? (The What)
Trong các hình thức tiêm phụ thuộc khác, dịch vụ được đưa vào class thông qua hàm khởi tạo (constructor) hoặc hàm cấu hình (setter) và được lưu trữ thành các thuộc tính (properties) sống suốt vòng đời của đối tượng đó.
Ngược lại, Method Injection loại bỏ hoàn toàn việc lưu trữ trạng thái nội bộ. Phụ thuộc (Dependency) chỉ được truyền trực tiếp vào tham số của một phương thức cụ thể ngay tại thời điểm phương thức đó được gọi. Khi hàm thực thi xong, phụ thuộc đó cũng biến mất cùng phạm vi thực thi (scope).
2. "Quen Mà Lạ": Minh Họa Bằng Laravel Controller Action Injection
Nếu bạn viết code Laravel hàng ngày, bạn chắc chắn đã dùng Method Injection thông qua cơ chế Action Injection của Service Container. Hãy nhìn ví dụ quen thuộc sau:
namespace App\Http\Controllers;
use App\Models\Order;
use App\Services\PdfInvoiceGenerator;
use Illuminate\Http\Request;
class InvoiceController extends Controller
{
// 💥 Method Injection xuất hiện ngay tại đây!
public function download(Request $request, Order $order, PdfInvoiceGenerator $pdfGenerator)
{
// $pdfGenerator được Container tự động tiêm vào đúng thời điểm hàm này chạy
return $pdfGenerator->generateStream($order);
}
}
- Điều gì đang xảy ra bên dưới? Khi một HTTP Request bắn vào route
invoice/download/{order}, Laravel IoC Container sẽ tự động đọc danh sách tham số của hàmdownload, nhận diện rằng hàm này cần mộtPdfInvoiceGenerator, tự động khởi tạo nó và nhét thẳng vào method. Bạn không cần phải khai báo nó ở Constructor của Controller nữa!
3. Khi Nào Nên Sử Dụng Method Injection?
Method Injection không phải là giải pháp thay thế hoàn toàn cho Constructor Injection, mà nó phát huy tối đa sức mạnh trong các kịch bản đặc thù sau:
- Dịch vụ chỉ dùng một lần duy nhất (Transient Dependency): Nếu một dịch vụ cực kỳ chuyên biệt và chỉ cần thiết cho một nghiệp vụ độc lập nằm trong một hàm cụ thể (ví dụ: hàm xuất PDF, hàm gửi mã OTP nhanh), việc tiêm nó qua Constructor sẽ làm thừa thãi trạng thái của cả class. Đưa nó trực tiếp vào Method là lựa chọn sạch sẽ nhất.
- Tránh hiện tượng "Constructor Bloat": Khi một Controller có 10 action khác nhau, mỗi action cần một service riêng biệt. Nếu bạn tiêm tất cả qua Constructor, constructor sẽ phình to với 10 dependencies khác nhau dù có action chỉ dùng đến đúng 1 dịch vụ. Method Injection giúp cô lập dependency nào ra action nấy.
- Trạng thái không chia sẻ (Stateless Actions): Đảm bảo tính độc lập giữa các lần gọi hàm, không bị lưu trữ giữ liệu rác bên trong các thuộc tính của class.
4. So Sánh Nhanh 4 Hình Thức Dependency Injection
| Tiêu chí | Constructor Injection | Setter Injection | Interface Injection | Method Injection |
|---|---|---|---|---|
| Thời điểm tiêm | Khi khởi tạo đối tượng (new) |
Bất cứ lúc nào sau khi khởi tạo | Thông qua hợp đồng Interface | Ngay khi gọi phương thức |
| Mức độ phổ biến | Cao nhất (Chuẩn vàng) | Thấp (Dùng cho cấu hình động) | Rất thấp (Dùng cho kiến trúc Plugin) | Rất cao (Trong Controllers / Handlers) |
| Tính bất biến (Immutability) | Tuyệt đối (nếu dùng readonly) |
Kém (có thể bị thay đổi liên tục) | Trung bình | Tuyệt đối (chỉ sống trong scope hàm) |
💡 Lời Kết
Hiểu rõ Method Injection giúp bạn linh hoạt hơn trong tư duy thiết kế API và Controller. Không phải lúc nào cũng cần nhồi nhét mọi thứ vào Constructor; đôi khi, việc let cho các dịch vụ "đến và đi" ngay trong phạm vi của một phương thức xử lý chính là chìa khóa để giữ cho mã nguồn gọn gàng, tường minh và tối ưu hiệu năng nhất.
All rights reserved