Ninject là gì và bạn sử dụng nó khi nào?

Ninject là bộ phun phụ thuộc cho .NET, hiện thực hóa mẫu Dependency Injection (dạng Inversion of Control pattern).

Giả sử bạn có hai lớp DbRepositoryvà Controller:



class Controller { private DbRepository _repository; // … some methods that uses _repository } class DbRepository { // … some bussiness logic here … }

Vì vậy, bây giờ bạn có hai vấn đề:

  1. Bạn phải khởi tạo _repositoryđể sử dụng nó. Bạn có một số tùy chọn để thực hiện việc này:

    1. Theo cách thủ công, trong hàm tạo. Nhưng điều gì sẽ xảy ra nếu phương thức khởi tạo của DbRepository thay đổi? Bạn sẽ cần phải viết lại Controllerlớp của mình vì mã của nó phụ thuộc vào đã được thay đổi. Không khó nếu bạn chỉ có một Controller, nhưng nếu bạn có một vài lớp phụ thuộc vào bạn, Repositorybạn có một vấn đề thực sự.
    2. Bạn có thể sử dụng bộ định vị dịch vụ hoặc nhà máy. Nhưng bây giờ bạn phải phụ thuộc vào bộ định vị dịch vụ của mình. Bạn có bộ định vị dịch vụ toàn cầu và tất cả mã phải sử dụng nó. Bạn sẽ thay đổi hành vi của bộ định vị dịch vụ như thế nào khi bạn cần sử dụng nó trong một phần của mã cho logic kích hoạt nhưng cho một cái gì đó khác trong phần khác của mã của bạn? Chỉ có một cách – chuyển bộ định vị dịch vụ qua các hàm tạo. Nhưng với ngày càng nhiều lớp học, bạn sẽ cần phải vượt qua nó nhiều lần hơn và nhiều hơn. Dù sao, đó là một suy nghĩ tốt nhưng về lâu dài, đó là một ý kiến ​​tồi.

      class Controller { private DbRepository _repository; public Controller() { _repository = sentayho.com.vn<DbRepository>() } // … some methods that uses _repository }

    3. Bạn có thể sử dụng tiêm phụ thuộc. Nhìn vào mã:

      class Controller { private IRepository _repository; public Controller(IRepository repository) { _repository = repository; } }

      Bây giờ khi bạn cần bộ điều khiển của mình, bạn viết: sentayho.com.vn<Controller>();hoặc sentayho.com.vn<Controller>();. Bạn có thể chuyển đổi giữa các trình giải quyết phụ thuộc nhanh như bạn muốn. Xem? Thật đơn giản, bạn không cần phải viết nhiều.

  2. Bạn không thể tạo các bài kiểm tra đơn vị cho nó. Của bạn Controllercó sự phụ thuộc vào DbRepositoryvà nếu bạn muốn thử nghiệm một số phương pháp sử dụng kho lưu trữ, mã của bạn sẽ đi đến cơ sở dữ liệu và yêu cầu nó cung cấp dữ liệu. Đó là chậm, rất chậm. Nếu mã của bạn DbRepositorythay đổi, bài kiểm tra đơn vị của bạn Controllersẽ giảm. Chỉ kiểm tra tích hợp phải cảnh báo bạn về ‘sự cố’ trong trường hợp này. Những gì bạn cần trong các bài kiểm tra đơn vị – là cô lập các lớp của bạn và chỉ kiểm tra một lớp trong một bài kiểm tra (trong lý tưởng – chỉ một phương pháp). Nếu DbRepositorymã của bạn không thành công, bạn sẽ nghĩ rằng Controllermã đó không thành công – và điều đó thật tệ (ngay cả khi bạn đã kiểm tra DbRepositoryvàController- cả hai đều sẽ thất bại và bạn có thể bắt đầu từ sai chỗ). Phải mất rất nhiều thời gian để xác định lỗi thực sự nằm ở đâu. Bạn cần biết rằng lớp A là tốt, và đó là lớp B, nơi có điều gì đó không thành công.

  3. Khi bạn muốn thay thế DbRepositorybằng một thứ khác trong tất cả các lớp của mình, bạn phải làm rất nhiều việc.

  4. Bạn không thể dễ dàng kiểm soát thời gian tồn tại của DbRepository. Một đối tượng của lớp này được tạo khi khởi tạo Controllervà bị xóa khi Controllerbị xóa. Không có sự chia sẻ giữa các trường hợp khác nhau của Controllerlớp và không có sự chia sẻ giữa các lớp khác. Với Ninject, bạn có thể chỉ cần viết:

    kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope();

Một tính năng đặc biệt của tiêm phụ thuộc – phát triển nhanh nhẹn! Bạn mô tả rằng bộ điều khiển của bạn sử dụng một kho lưu trữ có giao diện IRepository. Bạn không cần phải viết DbRepository, bạn có thể chỉ cần tạo một MemoryRepositorylớp và phát triển Controllertrong khi một người khác phát triển DbRepository. Khi công việc DbRepositoryhoàn tất, bạn chỉ cần rebind trong trình giải quyết phụ thuộc của mình mà mặc định IRepositorybây giờ là DbRepository. Có rất nhiều bộ điều khiển? Tất cả chúng bây giờ sẽ sử dụng DbRepository. Thật tuyệt.

Đọc thêm:

  1. Đảo ngược kiểm soát (wiki)
  2. Chèn ép phụ thuộc (wiki)
  3. Đảo ngược vùng chứa điều khiển và mẫu tiêm phụ thuộc (Martin Fowler)