Trên thực tế, cách "đúng" là hoàn toàn KHÔNG sử dụng nhà máy trừ khi hoàn toàn không có lựa chọn nào khác (như trong thử nghiệm đơn vị và các giả định nhất định - đối với mã sản xuất bạn KHÔNG sử dụng nhà máy)! Làm như vậy thực sự là một mô hình chống và nên tránh bằng mọi giá. Toàn bộ điểm phía sau một thùng chứa DI là cho phép tiện ích thực hiện công việc cho bạn.
Như đã nêu ở trên trong một bài viết trước, bạn muốn tiện ích IoC của mình chịu trách nhiệm tạo ra các đối tượng phụ thuộc khác nhau trong ứng dụng của bạn. Điều đó có nghĩa là để cho tiện ích DI của bạn tự tạo và quản lý các phiên bản khác nhau. Đây là toàn bộ điểm phía sau DI - các đối tượng của bạn KHÔNG BAO GIỜ biết cách tạo và / hoặc quản lý các đối tượng mà chúng phụ thuộc vào. Để làm khác phá vỡ khớp nối lỏng lẻo.
Chuyển đổi một ứng dụng hiện có thành tất cả DI là một bước tiến lớn, nhưng bỏ qua những khó khăn rõ ràng khi làm như vậy, bạn cũng sẽ muốn (chỉ để làm cho cuộc sống của bạn dễ dàng hơn một chút) để khám phá một công cụ DI sẽ tự động thực hiện phần lớn các liên kết của bạn (cốt lõi của thứ gì đó như Ninject là các "kernel.Bind<someInterface>().To<someConcreteClass>()"
cuộc gọi mà bạn thực hiện để khớp với các khai báo giao diện của bạn với các lớp cụ thể mà bạn muốn sử dụng để triển khai các giao diện đó. Đó là các lệnh gọi "Bind" cho phép tiện ích DI của bạn chặn các cuộc gọi của nhà xây dựng của bạn và cung cấp Các thể hiện đối tượng phụ thuộc cần thiết. Một hàm tạo điển hình (mã giả được hiển thị ở đây) cho một số lớp có thể là:
public class SomeClass
{
private ISomeClassA _ClassA;
private ISomeOtherClassB _ClassB;
public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
{
if (aInstanceOfA == null)
throw new NullArgumentException();
if (aInstanceOfB == null)
throw new NullArgumentException();
_ClassA = aInstanceOfA;
_ClassB = aInstanceOfB;
}
public void DoSomething()
{
_ClassA.PerformSomeAction();
_ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
}
}
Lưu ý rằng không ở đâu trong mã đó là bất kỳ mã nào được tạo / quản lý / phát hành, ví dụ của someConcittleClassA hoặc của someOtherConcittleClassB. Như một vấn đề của thực tế, cả lớp cụ thể thậm chí không được tham chiếu. Vậy ... phép thuật đã xảy ra ở đâu?
Trong phần khởi động của ứng dụng của bạn, phần sau đã diễn ra (một lần nữa, đây là mã giả nhưng nó khá gần với thứ thật (Ninject) ...):
public void StartUp()
{
kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}
Một đoạn mã nhỏ đó bảo tiện ích Ninject tìm kiếm các hàm tạo, quét chúng, tìm các thể hiện của các giao diện mà nó đã được cấu hình để xử lý (đó là các lệnh gọi "Bind"), sau đó tạo và thay thế một thể hiện của lớp cụ thể ở bất cứ đâu ví dụ được tham chiếu.
Có một công cụ hay bổ sung cho Ninject rất hay gọi là Ninject.Extensions.Conventions (một gói NuGet khác) sẽ thực hiện phần lớn công việc này cho bạn. Không phải từ bỏ trải nghiệm học tập tuyệt vời mà bạn sẽ trải qua khi bạn tự xây dựng điều này, nhưng để bắt đầu, đây có thể là một công cụ để điều tra.
Nếu bộ nhớ phục vụ, Unity (chính thức từ Microsoft bây giờ là một dự án Nguồn mở) có một cuộc gọi phương thức hoặc hai thực hiện cùng một công cụ, các công cụ khác có các trình trợ giúp tương tự.
Dù bạn chọn con đường nào, chắc chắn hãy đọc cuốn sách của Mark Seemann cho phần lớn khóa đào tạo DI của bạn, tuy nhiên, cần phải chỉ ra rằng ngay cả "Những người vĩ đại" của thế giới công nghệ phần mềm (như Mark) cũng có thể mắc lỗi rõ ràng - Mark đã quên tất cả về Ninject trong cuốn sách của mình vì vậy đây là một tài nguyên khác được viết riêng cho Ninject. Tôi có nó và nó rất hay: Làm chủ Ninject cho Dependency Injection