Sự khác biệt giữa tiêm phụ thuộc (DI) và đảo ngược kiểm soát (IOC)


117

Tôi đã nhìn thấy rất nhiều tài liệu tham khảo về Dependency Injection (DI) & Inversion Of Control (IOC), nhưng tôi thực sự không biết liệu có sự khác biệt giữa chúng hay không.

Tôi muốn bắt đầu sử dụng một hoặc cả hai, nhưng tôi hơi bối rối về việc chúng khác nhau như thế nào.


Đảo ngược điều khiển thường đề cập đến "các thùng chứa" trong khi Dependency Injection đề cập đến mẫu thực tế. Nhưng họ đi tay trong tay. Tôi khuyên bạn nên đọc bài viết của Martin Fowler để hiểu rõ hơn về chủ đề này.
Ben Hoffstein

Dependency Injection là một việc mà bạn làm, điều này dẫn đến một cấu trúc lệnh gọi là Inversion of Control. Chúng vốn đã được liên kết.

2
DI là một dạng của IoC, tôi đã đưa ra một lời giải thích khá chi tiết về DI và IoC trong câu trả lời này

2
Tôi muốn nói rằng DI là trường hợp đặc biệt của IOC. Điều khiển truyền thống đi mô-đun-> mô-đun yêu cầu từ trình quản lý mô-đun, trong DI, nó được chuyển sang trình quản lý mô-đun -> nhận phụ thuộc được yêu cầu từ mô-đun.
Rafał Dowgird

Vì vậy, nói cách khác, về cơ bản IoC là một triển khai sử dụng DI. Tôi có nhận được điều đó một cách chính xác?
dance2die

Câu trả lời:


53

Định nghĩa

Đảo ngược kiểm soát là một mô hình thiết kế với mục tiêu giảm nhận thức về việc triển khai cụ thể từ mã khung ứng dụng và cung cấp thêm quyền kiểm soát cho các thành phần cụ thể của miền trong ứng dụng của bạn. Trong một hệ thống được thiết kế từ trên xuống truyền thống, luồng logic của ứng dụng và nhận thức phụ thuộc chảy từ các thành phần hàng đầu, các thành phần được thiết kế trước, đến các thành phần được thiết kế cuối cùng. Như vậy, đảo ngược kiểm soát là một sự đảo ngược gần như theo nghĩa đen của kiểm soát và nhận thức phụ thuộc trong một ứng dụng.

Nội dung phụ thuộc là một mẫu được sử dụng để tạo các thể hiện của các lớp mà các lớp khác dựa vào mà không biết tại thời điểm biên dịch triển khai nào sẽ được sử dụng để cung cấp chức năng đó.

Làm việc cùng nhau

Đảo ngược điều khiển có thể sử dụng phép nội xạ phụ thuộc vì cần một cơ chế để tạo ra các thành phần cung cấp chức năng cụ thể. Các tùy chọn khác tồn tại và được sử dụng, ví dụ như trình kích hoạt, phương thức xuất xưởng, v.v., nhưng các khung công tác không cần tham chiếu các lớp tiện ích đó khi các lớp khung có thể chấp nhận phụ thuộc mà chúng cần.

Ví dụ

Một ví dụ về các khái niệm này tại nơi làm việc là khung trình cắm trong Reflector . Các trình cắm có rất nhiều quyền kiểm soát hệ thống mặc dù ứng dụng không biết gì về các trình cắm trong thời gian biên dịch. Một phương thức duy nhất được gọi trên mỗi trình cắm đó, Khởi tạo nếu bộ nhớ phục vụ, chuyển giao quyền điều khiển cho trình cắm. Khung không biết họ sẽ làm gì, nó chỉ cho phép họ làm điều đó. Kiểm soát đã được lấy từ ứng dụng chính và được trao cho thành phần thực hiện công việc cụ thể; đảo ngược kiểm soát.

Khung ứng dụng cho phép truy cập vào chức năng của nó thông qua nhiều nhà cung cấp dịch vụ. Một trình cắm thêm được cung cấp các tham chiếu đến các nhà cung cấp dịch vụ khi nó được tạo. Các phụ thuộc này cho phép trình cắm thêm các mục menu riêng của nó, thay đổi cách hiển thị các tệp, hiển thị thông tin của chính nó trong các bảng thích hợp, v.v. Vì các phụ thuộc được truyền qua giao diện, việc triển khai có thể thay đổi và các thay đổi sẽ không phá vỡ mã miễn là hợp đồng vẫn còn nguyên.

Vào thời điểm đó, một phương thức xuất xưởng đã được sử dụng để tạo các trình cắm bằng cách sử dụng thông tin cấu hình, sự phản chiếu và đối tượng Trình kích hoạt (ít nhất là trong .NET). Ngày nay, có các công cụ, MEF cho một, cho phép phạm vi tùy chọn rộng hơn khi tiêm phụ thuộc bao gồm khả năng khung ứng dụng chấp nhận danh sách bổ trợ làm phụ thuộc.

Tóm lược

Mặc dù các khái niệm này có thể được sử dụng và cung cấp các lợi ích một cách độc lập, cùng với nhau, chúng cho phép viết mã linh hoạt, có thể sử dụng lại và kiểm tra được nhiều hơn. Như vậy, chúng là những khái niệm quan trọng trong việc thiết kế các giải pháp hướng đối tượng.


3
Không, IoC là một khái niệm cũ hơn và nó độc lập với DI (không phụ thuộc vào IoC). Ví dụ: lấy khung Struts (Java): nó phụ thuộc rất nhiều vào IoC, nhưng không sử dụng DI.
Rogério

1
@ Rogério - Bạn nói rõ rằng hai khái niệm này không yêu cầu nhau. Tôi đã cập nhật câu trả lời của mình để làm rõ điều đó và sau đó nhanh chóng mô tả cách một số khung sử dụng chúng cùng nhau để cho phép mã được ghép lỏng lẻo hơn.
Chuck

Ứng dụng đơn giản nhất của IoC, có lẽ sẽ là ActionListener. Thay vì xử lý thủ tục mã, mã xử lý sự kiện được ủy quyền cho mã tùy chỉnh. Từ đây đảo ngược sự kiểm soát.
chước

0

Bài viết hay để hiểu IOC và DI http://martinfowler.com/articles/injection.html

IOC (Đảo ngược kiểm soát)

IOC có nghĩa là

  1. mã hóa giao diện (một thành phần nên phụ thuộc vào giao diện của thành phần khác chứ không phụ thuộc vào impl), v.v.

    interface iComp_2 {...}
    
    class Comp_1 {
        iComp_2 c2 = ….;
    }
    
  2. loại bỏ mã cụ thể thực hiện thành phần, ví dụ

    Comp_1 {
        iComp_2 c2 = getComp_2_Impl(); // not new Comp_2_Impl();
    }
    

IOC có thể đạt được bằng một trong các cách sau:

1. DI (Tiêm phụ thuộc)

3 types of DI

1.1 Constructor Injection

1.2 Setter Injection

1.3 Interface Injection

2. Định vị dịch vụ

Container DI (Dependency Injection)

Xác định thời gian thực thi và không biên dịch thời gian: xác định trong thời gian chạy mà việc triển khai cụ thể của giao diện sẽ được sử dụng dựa trên một số tệp cấu hình (vì vậy tại thời gian biên dịch, chúng tôi không biết sẽ sử dụng impl nào và do đó làm tăng khả năng cấu hình của ứng dụng) . Đây là một triển khai trong đó mối quan hệ cụ thể giữa các mô-đun khác nhau được quyết định tại "thời gian chạy".

Khởi tạo impl sau khi tiêm phụ thuộc: sau khi xác định impl, nó khởi tạo impl đó bằng cách trước tiên tạo tất cả các phụ thuộc của nó (được chỉ định trong tệp cấu hình) và sau đó tiêm các phụ thuộc đó vào implant đó

Quản lý vòng đời ngay lập tức: Các thùng chứa DI thường chỉ giữ một tham chiếu đến các đối tượng mà nó cần để quản lý vòng đời hoặc được sử dụng lại cho các mũi tiêm trong tương lai, như singletons hoặc flyweights. Khi được cấu hình để tạo phiên bản mới của một số thành phần cho mỗi cuộc gọi đến vùng chứa, vùng chứa thường chỉ quên đối tượng được tạo. Nếu không, trình thu gom rác sẽ gặp khó khăn khi thu thập tất cả các đối tượng này khi không còn sử dụng.


6
Bạn đã thực sự đọc bài viết "tiêm"? IOC không có nghĩa là câu trả lời này nói gì, hoàn toàn không.
Rogério

-3

Tôi muốn nói "Đảo ngược điều khiển" là một cách để thiết kế một hệ thống trong đó tất cả các mô-đun được cho là của các thực thể trừu tượng.

Và, "Dependency Injection" là một triển khai trong đó mối quan hệ cụ thể giữa các mô-đun khác nhau được quyết định tại "thời gian chạy".


-4

Đảo ngược điều khiển là một khái niệm chung, trong các ngôn ngữ chức năng thường được thực hiện bằng cách sử dụng các phần tiếp theo. Điều này cho phép bạn viết một API trong đó cả hai bên là 'người gọi' và không ai là 'callee'. Trong các môi trường tĩnh khác, bạn không có sự thuận tiện này, vì vậy bạn cần hack này để chèn gợi ý vào luồng điều khiển.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.