Có một cuộc tranh luận cũ, cũ đang diễn ra về cách tốt nhất để thực hiện tiêm phụ thuộc.
Việc cắt lò xo ban đầu khởi tạo một đối tượng đơn giản, và sau đó thêm các phụ thuộc mặc dù các phương thức setter.
Nhưng sau đó, một nhóm lớn người đã nhấn mạnh rằng tiêm phụ thuộc thông qua các tham số của hàm tạo là cách chính xác để làm điều đó.
Sau đó, gần đây, khi việc sử dụng sự phản chiếu trở nên phổ biến hơn, việc đặt các giá trị của các thành viên tư nhân trực tiếp, mà không cần setters hay constructor, trở thành cơn thịnh nộ.
Vì vậy, nhà xây dựng đầu tiên của bạn phù hợp với cách tiếp cận thứ hai để tiêm phụ thuộc. Nó cho phép bạn làm những điều tốt đẹp như tiêm giả để thử nghiệm.
Nhưng các nhà xây dựng không có đối số có vấn đề này. Vì nó khởi tạo các lớp triển khai cho PaypalCreditCardProcessor
và DatabaseTransactionLog
, nó tạo ra sự phụ thuộc cứng, thời gian biên dịch vào PayPal và Cơ sở dữ liệu. Nó chịu trách nhiệm xây dựng và cấu hình toàn bộ cây phụ thuộc một cách chính xác.
Hãy tưởng tượng rằng bộ xử lý PayPay là một hệ thống con thực sự phức tạp và ngoài ra còn có rất nhiều thư viện hỗ trợ. Bằng cách tạo một phụ thuộc thời gian biên dịch trên lớp triển khai đó, bạn đang tạo một liên kết không thể phá vỡ đến toàn bộ cây phụ thuộc đó. Độ phức tạp của biểu đồ đối tượng của bạn vừa tăng lên theo một độ lớn, có thể là hai.
Rất nhiều vật phẩm trong cây phụ thuộc sẽ trong suốt, nhưng rất nhiều trong số chúng cũng cần phải được khởi tạo. Vấn đề là, bạn sẽ không thể khởi tạo a PaypalCreditCardProcessor
.
Ngoài khởi tạo, mỗi đối tượng sẽ cần các thuộc tính được áp dụng từ cấu hình.
Nếu bạn chỉ có một phụ thuộc vào giao diện và cho phép một nhà máy bên ngoài xây dựng và tiêm phụ thuộc, họ sẽ cắt toàn bộ cây phụ thuộc PayPal và sự phức tạp của mã của bạn dừng lại ở giao diện.
Có các lợi ích khác, như là chỉ định các lớp triển khai trong cấu hình (nghĩa là tại thời gian chạy thay vì thời gian biên dịch) hoặc có đặc tả phụ thuộc động hơn thay đổi, theo môi trường (kiểm tra, tích hợp, sản xuất).
Ví dụ: giả sử PayPalProcessor có 3 đối tượng phụ thuộc và mỗi đối tượng phụ thuộc đó có thêm hai đối tượng. Và tất cả những đối tượng đó phải lấy các thuộc tính từ cấu hình. Mã như sẽ đảm nhận trách nhiệm xây dựng tất cả những thứ đó, thiết lập các thuộc tính từ cấu hình, v.v. - tất cả các mối quan tâm mà khung DI sẽ quan tâm.
Ban đầu có vẻ không rõ ràng về những gì bạn che chắn bản thân bằng cách sử dụng khung DI, nhưng nó sẽ tăng lên và trở nên rõ ràng theo thời gian. (lol tôi nói từ kinh nghiệm đã cố gắng làm điều đó một cách khó khăn)
...
Trong thực tế, ngay cả đối với một chương trình thực sự nhỏ bé, tôi thấy tôi kết thúc việc viết theo kiểu DI và chia các lớp thành các cặp thực hiện / nhà máy. Đó là, nếu tôi không sử dụng khung DI như Spring, tôi chỉ cần kết hợp một số lớp học đơn giản.
Điều đó cung cấp sự phân tách các mối quan tâm để lớp của tôi có thể thực hiện điều đó và lớp nhà máy chịu trách nhiệm xây dựng và định cấu hình công cụ.
Không phải là một cách tiếp cận bắt buộc, nhưng FWIW
...
Tổng quát hơn, mẫu giao diện DI / làm giảm độ phức tạp của mã của bạn bằng cách thực hiện hai điều:
Trên hết, vì khởi tạo và cấu hình đối tượng là một nhiệm vụ khá quen thuộc, khung DI có thể đạt được rất nhiều tính kinh tế theo quy mô thông qua ký hiệu chuẩn & sử dụng các thủ thuật như phản xạ. Phân tán những mối quan tâm tương tự xung quanh các lớp học kết thúc thêm nhiều lộn xộn hơn người ta nghĩ.