Câu hỏi Đảo ngược kiểm soát là gì?


Inversion of Control (hoặc IoC) có thể khá khó hiểu khi nó lần đầu tiên gặp phải.

  1. Nó là gì?
  2. Nó giải quyết vấn đề gì?
  3. Khi nào nó thích hợp và khi nào thì không?

1430
2017-08-06 03:35


gốc


Vấn đề với hầu hết các câu trả lời này là thuật ngữ được sử dụng. Thùng chứa là gì? Đảo ngược? Phụ thuộc? Giải thích nó bằng các thuật ngữ của giáo dân mà không có những từ ngữ lớn. - kirk.burleson
Xem thêm trên Programmers.SE: Tại sao Inversion of Control lại được đặt tên theo cách đó? - Izkata
Nó là Dependency Injection (DI) - xem Martin Fowlers 'descrition tại đây: martinfowler.com/articles/injection.html#InversionOfControl - Ricardo Sanchez
Điều này kinda pics nó lên - totymedli
Nó là một tính từ, không phải là danh từ, nó không phải là một điều, nó là một mô tả về một sự thay đổi được thực hiện cho mã, nơi mà sự kiểm soát của dòng chảy là trong đại biểu, không phải là thùng chứa. - Martin Spamer


Các câu trả lời:


Các mẫu Inversion of Control (IoC) và Dependency Injection (DI) là tất cả về việc loại bỏ các phụ thuộc từ mã của bạn.

Ví dụ: giả sử ứng dụng của bạn có thành phần soạn thảo văn bản và bạn muốn cung cấp kiểm tra chính tả. Mã tiêu chuẩn của bạn sẽ trông giống như sau:

public class TextEditor {

    private SpellChecker checker;

    public TextEditor() {
        this.checker = new SpellChecker();
    }
}

Những gì chúng tôi đã làm ở đây tạo ra sự phụ thuộc giữa TextEditor và SpellChecker. Trong một kịch bản IoC, thay vào đó chúng ta sẽ làm như sau:

public class TextEditor {

    private IocSpellChecker checker;

    public TextEditor(IocSpellChecker checker) {
        this.checker = checker;
    }
}

Trong ví dụ mã đầu tiên, chúng tôi đang khởi tạo SpellChecker (this.checker = new SpellChecker();), có nghĩa là TextEditor lớp học trực tiếp phụ thuộc vào SpellChecker lớp học.

Trong ví dụ mã thứ hai, chúng tôi đang tạo một trừu tượng bằng cách SpellChecker lớp phụ thuộc vào TextEditor chữ ký hàm tạo (không khởi tạo sự phụ thuộc trong lớp). Điều này cho phép chúng ta gọi sự phụ thuộc sau đó chuyển nó tới lớp TextEditor như sau:

SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);

Bây giờ khách hàng tạo ra TextEditor lớp học có quyền kiểm soát SpellChecker triển khai để sử dụng vì chúng tôi đang tiêm phụ thuộc vào TextEditor Chữ ký.

Đây chỉ là một ví dụ đơn giản, có một loạt bài viết hay bởi Simone Busoli giải thích chi tiết hơn.


1140
2017-08-06 07:22



Ví dụ rõ ràng. Tuy nhiên, giả sử thay vì yêu cầu giao diện ISpellChecker được truyền cho hàm tạo của đối tượng, chúng ta đã tiếp xúc nó như một thuộc tính có thể cài đặt (hoặc phương thức SetSpellChecker). Điều này vẫn cấu thành IoC? - devios1
chainguy1337 - có nó sẽ. Sử dụng setters như vậy được gọi là setter injection như trái ngược với constructor injection (cả hai dependency injection technique). IoC là một mô hình khá chung chung, nhưng sự phụ thuộc tiêm acheives IoC - Schneider
Mặc dù có rất nhiều phiếu bầu, câu trả lời này là không chính xác. Xin vui lòng xem martinfowler.com/articles/injection.html#InversionOfControl. Đặc biệt, lưu ý phần nói rằng "Inversion of Control quá chung chung một thuật ngữ, và do đó mọi người thấy nó khó hiểu. Kết quả là có rất nhiều thảo luận với những người ủng hộ IoC khác nhau, chúng tôi đã đặt tên Dependency Injection". - Rogério
Tôi đồng ý với @Rogeria. điều này không giải thích tại sao nó được gọi là IoC và tôi ngạc nhiên bởi số lượng phiếu bầu ;-) - Aravind R. Yarram
Tôi đứng về phía với @Rogerio và @Pangea. Đây có thể là một ví dụ tốt cho -sự phun nhưng không phải là câu trả lời hay cho câu hỏi ban đầu. IoC, như được xác định bởi Fowler, có thể được thực hiện mà không cần sử dụng bất kỳ loại tiêm nào, ví dụ: bằng cách sử dụng dịch vụ định vị hoặc thậm chí thừa kế đơn giản. - mtsz


Đảo ngược kiểm soát là những gì bạn nhận được khi gọi lại chương trình của bạn, ví dụ: như một chương trình gui.

Ví dụ: trong menu trường học cũ, bạn có thể có:

print "enter your name"
read name
print "enter your address"
read address
etc...
store in database

qua đó kiểm soát luồng tương tác của người dùng.

Trong một chương trình GUI hoặc somesuch, thay vào đó chúng ta nói

when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase

Vì vậy, bây giờ điều khiển được đảo ngược ... thay vì máy tính chấp nhận đầu vào của người dùng theo thứ tự cố định, người dùng kiểm soát thứ tự mà dữ liệu được nhập vào và khi dữ liệu được lưu trong cơ sở dữ liệu.

Về cơ bản, mọi thứ có vòng lặp sự kiện, gọi lại hoặc trình kích hoạt thực thi rơi vào danh mục này.


495
2017-08-06 05:42



không đánh dấu anh chàng này xuống. về mặt kỹ thuật, anh ấy đúng martinfowler.com/bliki/InversionOfControl.html IoC là một hiệu trưởng rất chung chung. Luồng kiểm soát được "đảo ngược" bằng cách tiêm phụ thuộc vì bạn đã ủy quyền một cách hiệu quả các phụ thuộc vào một số hệ thống bên ngoài (ví dụ: thùng chứa IoC) - Schneider
Đồng ý với bình luận của Schneider. 5 downvotes? Tâm trí boggles, vì đây là câu trả lời duy nhất thực sự chính xác. Lưu ý mở: 'như một chương trình gui. ' Dependency injection chỉ là việc thực hiện thường thấy nhất của IoC. - Jeff Sternal
Thật vậy, đây là một trong số ít chính xác anwsers! Các bạn, IoC là không phải về cơ bản là phụ thuộc. Không có gì. - Rogério
1 - Đây là một mô tả hay (ví dụ) của tuyên bố sau đây của Martin Fowler - "Giao diện người dùng sớm được kiểm soát bởi chương trình ứng dụng. Bạn sẽ có một chuỗi các lệnh như" Nhập tên "," nhập địa chỉ "; Với giao diện đồ họa (hoặc thậm chí dựa trên màn hình), khung UI sẽ chứa vòng lặp chính này và chương trình của bạn thay vào đó cung cấp trình xử lý sự kiện cho các trường khác nhau trên màn hình. chương trình đã bị đảo ngược, chuyển bạn ra khỏi khung công tác. " - Ashish Gupta
Bây giờ tôi hiểu tại sao đôi khi nó được gọi là "Nguyên tắc của Hollywood: Đừng gọi cho chúng tôi, chúng tôi sẽ gọi cho bạn" - Alexander Suraphel


Đảo ngược kiểm soát là gì?

Nếu bạn làm theo hai bước đơn giản này, bạn đã thực hiện đảo ngược kiểm soát:

  1. Tách rời -phần làm việc khi nàophần làm việc.
  2. Đảm bảo rằng khi nào phần biết như ít càng tốt về  phần; và ngược lại.

Có một số kỹ thuật có thể cho mỗi bước này dựa trên công nghệ / ngôn ngữ bạn đang sử dụng để triển khai.

- -

Các đảo ngược một phần của Inversion of Control (IoC) là điều khó hiểu; bởi vì đảo ngược là thuật ngữ tương đối. Cách tốt nhất để hiểu IoC là quên đi từ đó!

- -

Ví dụ

  • Xử lý sự kiện. Xử lý sự kiện (phần việc cần làm) - Tăng sự kiện (phần việc cần làm)
  • Giao diện. Phần tử máy khách (phần làm việc) - Thực hiện giao diện thành phần (phần cần làm)
  • xUnit fixure. Thiết lập và TearDown (phần làm việc) - xUnit framework gọi tới Setup lúc đầu và TearDown ở phần cuối (khi cần làm)
  • Mẫu thiết kế phương thức mẫu. phương thức khuôn mẫu khi làm việc - phân lớp nguyên thủy thực hiện phần cần làm
  • Các phương thức chứa DLL trong COM. DllMain, DllCanUnload, v.v. (phần cần làm) - COM / OS (phần khi cần làm)

359
2017-07-22 17:34



Làm thế nào bạn đang nói giao diện. Thành phần client (khi làm việc) là "when" không có ý nghĩa khi chúng ta sử dụng các giao diện (Ex: Dependency Injection), chúng ta chỉ trừu tượng nó ra và cung cấp cho khách hàng sự linh hoạt về việc bổ sung thêm nhưng không có "khi nào" tham gia ở đó. Tôi đồng ý với "khi" trong trường hợp Tăng sự kiện xử lý sự kiện. - YakRangi
Bởi 'khách hàng thành phần' tôi có nghĩa là người dùng / khách hàng của giao diện. Khách hàng biết 'khi nào' để kích hoạt phần 'làm gì' cho dù mục đích là mở rộng chức năng hay không. - rpattabi
Hãy xem bài viết tuyệt vời này của Martin Fowler. Ông cho thấy cách giao diện làm cho phần cơ bản của đảo ngược kiểm soát: martinfowler.com/articles/injection.html#InversionOfControl - rpattabi
hai câu đầu tiên là rực rỡ. tuyệt vời !! hoàn hảo tách biệt khi làm việc và làm gì !! tôi không biết tại sao các câu trả lời khác lại nhận được rất nhiều upvotes. họ chỉ nói mã mà không có bất kỳ sự hiểu biết nào. - Amir Ziarati


Đảo ngược Kiểm soát là về việc phân tách các mối quan tâm.

Không có IoC: Bạn có một máy tính xách tay máy tính và bạn vô tình phá vỡ màn hình. Và darn, bạn tìm thấy cùng một màn hình máy tính xách tay mô hình là hư không trên thị trường. Vì vậy, bạn đang bị mắc kẹt.

Với IoC: Bạn có một máy tính để bàn máy tính và bạn vô tình phá vỡ màn hình. Bạn tìm thấy bạn chỉ có thể lấy gần như bất kỳ màn hình máy tính để bàn từ thị trường, và nó hoạt động tốt với máy tính để bàn của bạn.

Máy tính của bạn thực hiện thành công IoC trong trường hợp này. Nó chấp nhận một loại màn hình, trong khi máy tính xách tay không, nó cần một màn hình cụ thể để có được cố định.


90
2017-09-25 14:24



Jijong Hui Cái này xóa đầu tôi. - Arun Prasad E S
@Luo Jiong Hui Nice lời giải thích. - Sach
Hầu hết các mẫu thiết kế, nếu không phải tất cả, có đối tác của họ trong cuộc sống hàng ngày của chúng tôi mà chúng ta thấy và hiểu rất rõ. Cách hiểu hiệu quả nhất một mẫu thiết kế là biết các đối tác trong cuộc sống hàng ngày của họ. Và tôi tin rằng có rất nhiều. - Luo Jiong Hui


Đảo ngược điều khiển, (hoặc IoC), là về tự do (Bạn kết hôn, bạn mất quyền tự do và bạn đang bị kiểm soát. Bạn đã ly hôn, bạn vừa mới thực hiện Inversion of Control. Đó là điều chúng tôi gọi là "tách rời". Hệ thống máy tính tốt không khuyến khích mối quan hệ rất gần gũi.) linh hoạt hơn (Nhà bếp trong văn phòng của bạn chỉ phục vụ nước máy sạch, đó là lựa chọn duy nhất của bạn khi bạn muốn uống. Ông chủ của bạn đã thực hiện Inversion of Control bằng cách thiết lập một máy pha cà phê mới. ) và ít phụ thuộc hơn (Đối tác của bạn có một công việc, bạn không có việc làm, bạn phụ thuộc vào tài chính đối tác của bạn, vì vậy bạn được kiểm soát. Bạn tìm được một công việc, bạn đã thực hiện Inversion of Control. Hệ thống máy tính tốt khuyến khích sự phụ thuộc.)

Khi bạn sử dụng một máy tính để bàn, bạn đã slaved (hoặc nói, kiểm soát). Bạn phải ngồi trước một màn hình và nhìn vào nó. Sử dụng bàn phím để nhập và sử dụng chuột để điều hướng. Và một phần mềm được viết kém có thể làm bạn bực bội hơn. Nếu bạn thay thế máy tính để bàn của mình bằng máy tính xách tay, thì bạn sẽ đảo ngược phần nào điều khiển. Bạn có thể dễ dàng lấy nó và di chuyển xung quanh. Vì vậy, bây giờ bạn có thể kiểm soát nơi bạn đang có với máy tính của bạn, thay vì máy tính của bạn kiểm soát nó.

Bằng cách thực hiện Inversion of Control, người tiêu dùng phần mềm / đối tượng có nhiều điều khiển / tùy chọn hơn phần mềm / đối tượng, thay vì bị kiểm soát hoặc có ít tùy chọn hơn.

Với những ý tưởng trên trong tâm trí. Chúng tôi vẫn nhớ một phần quan trọng của IoC. Trong kịch bản của IoC, người tiêu dùng phần mềm / đối tượng là một khuôn khổ phức tạp. Điều đó có nghĩa là mã bạn đã tạo không được gọi bởi chính bạn. Bây giờ hãy giải thích tại sao cách này hoạt động tốt hơn cho một ứng dụng web.

Giả sử mã của bạn là một nhóm công nhân. Họ cần phải xây dựng một chiếc xe hơi. Những công nhân này cần một nơi và công cụ (một khung phần mềm) để xây dựng chiếc xe. A truyên thông khung phần mềm sẽ giống như một nhà để xe với nhiều công cụ. Vì vậy, các công nhân cần tự lập kế hoạch và sử dụng các công cụ để chế tạo xe. Xây dựng một chiếc xe không phải là một doanh nghiệp dễ dàng, nó sẽ thực sự khó khăn cho người lao động để lập kế hoạch và hợp tác đúng cách. A hiện đại khung phần mềm sẽ giống như một nhà máy xe hiện đại với tất cả các cơ sở và người quản lý tại chỗ. Người lao động không phải lập kế hoạch nào, người quản lý (một phần của khuôn khổ, họ là người thông minh nhất và lập kế hoạch tinh vi nhất) sẽ giúp phối hợp để người lao động biết khi nào cần làm công việc của họ (khung gọi mã của bạn). Người lao động chỉ cần đủ linh hoạt để sử dụng bất kỳ công cụ nào mà người quản lý cung cấp cho họ (bằng cách sử dụng Injection Dependency).

Mặc dù người lao động cho phép kiểm soát việc quản lý dự án ở cấp cao nhất đối với các nhà quản lý (khung công tác). Nhưng nó là tốt để có một số chuyên gia giúp đỡ. Đây là khái niệm về IoC thực sự đến từ.

Các ứng dụng web hiện đại với kiến ​​trúc MVC phụ thuộc vào khung làm việc định tuyến URL và đặt bộ điều khiển tại chỗ cho khuôn khổ để gọi.

Dependency Injection và Inversion of Control có liên quan. Dependency Injection đang ở vi mô mức độ và đảo ngược của kiểm soát là ở macro cấp độ. Bạn phải ăn từng miếng (thực hiện DI) để hoàn thành một bữa ăn (thực hiện IoC).


80
2018-03-04 19:33



Tôi đã bỏ phiếu cho việc so sánh DI với hôn nhân và IoC để ly hôn. - Marek Bar
Chết tiệt .. Hãy yêu nó !!! - Gowtham GS


Trước khi sử dụng Inversion of Control, bạn nên biết rõ thực tế rằng nó có ưu và khuyết điểm của nó và bạn nên biết tại sao bạn sử dụng nó nếu bạn làm như vậy.

Ưu điểm:

  • Mã của bạn được tách riêng để bạn có thể dễ dàng trao đổi việc triển khai giao diện với các triển khai thay thế
  • Nó là một động lực mạnh mẽ để mã hóa chống lại các giao diện thay vì triển khai
  • Nó rất dễ dàng để viết đơn vị kiểm tra mã của bạn bởi vì nó phụ thuộc vào không có gì khác hơn so với các đối tượng nó chấp nhận trong constructor / setters của nó và bạn có thể dễ dàng khởi tạo chúng với các đối tượng bên phải trong sự cô lập.

Nhược điểm:

  • IoC không chỉ chuyển đổi luồng điều khiển trong chương trình của bạn, nó cũng làm cho nó trở nên đáng kể. Điều này có nghĩa là bạn không còn có thể đọc mã của mình và nhảy từ nơi này sang nơi khác vì các kết nối bình thường trong mã của bạn không còn trong mã nữa. Thay vào đó, nó nằm trong các tệp cấu hình XML hoặc các chú thích và trong mã của thùng chứa IoC của bạn để diễn giải các siêu dữ liệu này.
  • Có một lớp lỗi mới, nơi bạn nhận được cấu hình XML hoặc chú thích sai và bạn có thể dành nhiều thời gian để tìm hiểu lý do tại sao container IoC của bạn đưa một tham chiếu null vào một trong các đối tượng của bạn trong các điều kiện nhất định.

Cá nhân tôi thấy điểm mạnh của IoC và tôi thực sự thích chúng nhưng tôi có xu hướng tránh IoC bất cứ khi nào có thể bởi vì nó biến phần mềm của bạn thành một tập hợp các lớp không còn là chương trình "thực" mà chỉ là Cấu hình XML hoặc siêu dữ liệu chú thích và sẽ giảm (và rơi) ngoài mà không có nó.


73
2018-02-12 14:31



Con đầu tiên không chính xác. Lý tưởng nhất là chỉ nên sử dụng 1 thùng chứa IOC trong mã của bạn, và đó là phương pháp chính của bạn. Mọi thứ khác nên hạ xuống từ đó - mwjackson
Tôi nghĩ ý anh là, bạn không thể chỉ đọc: myService.DoSomething () và đi đến định nghĩa của DoSomething, bởi vì với IoC, myService chỉ là một giao diện, và việc thực hiện thực tế là không rõ đối với bạn, trừ khi bạn nhìn nó trong tập tin cấu hình xml hoặc phương pháp chính nơi ioc của bạn được thiết lập. - chrismay
Đó là nơi Resharper giúp - "click go to implementation" trên giao diện. Tránh IoC (hoặc cụ thể hơn từ ví dụ của bạn) có thể cũng có nghĩa là bạn không kiểm tra đúng cách - IThasTheAnswer
Re: nó biến phần mềm của bạn thành một bộ sưu tập các lớp không còn là một chương trình "thực" mà chỉ là một thứ cần được đặt cùng với cấu hình XML hoặc siêu dữ liệu chú thích và sẽ giảm (và rơi) mà không có nó - Tôi nghĩ điều này rất gây hiểu nhầm. Điều tương tự cũng có thể nói về bất kỳ chương trình nào được viết trên đầu khung công tác. Sự khác biệt với một container IoC tốt là bạn có thể, nếu chương trình của bạn được thiết kế và viết tốt, lấy nó ra và cào trong một cái khác với những thay đổi tối thiểu cho mã của bạn, hoặc tung ra IoC hoàn toàn và xây dựng các đối tượng của bạn bằng tay . - The Awnry Bear
Rất vui được thấy câu trả lời trong thế giới thực như thế này! Tôi nghĩ rằng có rất nhiều lập trình viên có kinh nghiệm, thoải mái với thiết kế định hướng đối tượng và thực hành TDD, đã sử dụng giao diện, mẫu nhà máy, mô hình điều khiển sự kiện và chế nhạo ở nơi có ý nghĩa, trước khi từ "IoC" được phát minh. Thật không may quá nhiều nhà phát triển / "kiến trúc sư" tuyên bố thực hành không tốt nếu bạn không sử dụng các khung ưa thích của họ. Tôi thích thiết kế tốt hơn, sử dụng các khái niệm và công cụ ngôn ngữ được xây dựng sẵn, để đạt được cùng một mục tiêu với một phần nhỏ của sự phức tạp, tức là không có "clouding" việc triển khai như bạn nói :-) - Tony Wall


  1. Bài viết trên Wikipedia. Đối với tôi, đảo ngược kiểm soát là chuyển mã tuần tự bằng văn bản của bạn và biến nó thành một cấu trúc ủy quyền. Thay vì chương trình của bạn kiểm soát tất cả mọi thứ một cách rõ ràng, chương trình của bạn sẽ thiết lập một lớp hoặc thư viện với một số chức năng nhất định sẽ được gọi khi một số điều xảy ra.

  2. Nó giải quyết sự sao chép mã. Ví dụ, trong những ngày cũ bạn sẽ tự viết vòng lặp sự kiện của riêng bạn, bỏ phiếu cho các thư viện hệ thống cho các sự kiện mới. Ngày nay, hầu hết các API hiện đại, bạn chỉ cần nói cho các thư viện hệ thống biết những sự kiện nào bạn quan tâm và nó sẽ cho bạn biết khi nào chúng xảy ra.

  3. Đảo ngược kiểm soát là một cách thiết thực để giảm trùng lặp mã và nếu bạn thấy mình sao chép toàn bộ phương thức và chỉ thay đổi một đoạn mã nhỏ, bạn có thể xem xét giải quyết nó bằng cách đảo ngược kiểm soát. Đảo ngược kiểm soát được thực hiện dễ dàng trong nhiều ngôn ngữ thông qua các khái niệm về đại biểu, giao diện, hoặc thậm chí con trỏ chức năng thô.

    Nó không thích hợp để sử dụng trong mọi trường hợp, bởi vì dòng chảy của một chương trình có thể khó thực hiện hơn khi được viết theo cách này. Đó là một cách hữu ích để thiết kế các phương thức khi viết một thư viện sẽ được tái sử dụng, nhưng nó nên được sử dụng một cách tiết kiệm trong lõi của chương trình của riêng bạn trừ khi nó thực sự giải quyết được vấn đề sao chép mã.


55
2017-08-06 04:33



Tôi thấy rằng bài viết trên Wikipedia rất khó hiểu và cần sửa chữa. Xem trang thảo luận để biết cười. - devios1


Nhưng tôi nghĩ bạn phải rất cẩn thận với nó. Nếu bạn sẽ lạm dụng mô hình này, bạn sẽ làm cho thiết kế rất phức tạp và thậm chí mã phức tạp hơn.

Giống như trong ví dụ này với TextEditor: nếu bạn chỉ có một SpellChecker có lẽ nó không thực sự cần thiết để sử dụng IoC? Trừ khi bạn cần phải viết các bài kiểm tra đơn vị hoặc một cái gì đó ...

Dù sao thì cũng hợp lý. Mẫu thiết kế là thực hành tốt nhưng không phải Kinh Thánh được rao giảng. Đừng dán nó ở khắp mọi nơi.


39
2017-08-06 22:08



Làm thế nào để bạn biết rằng bạn sẽ chỉ có một bộ kiểm tra chính tả? - Trace


Giả sử bạn là một đối tượng. Và bạn đi đến một nhà hàng:

Không có IoC: bạn yêu cầu "táo" và bạn luôn phục vụ táo khi bạn hỏi thêm.

Với IoC: Bạn có thể yêu cầu "trái cây". Bạn có thể nhận được các loại trái cây khác nhau mỗi khi bạn được phục vụ. ví dụ như táo, cam hoặc dưa hấu.

Vì vậy, rõ ràng, IoC được ưa thích khi bạn thích các giống.


35
2017-09-25 14:00





IoC / DI cho tôi đang đẩy phụ thuộc vào các đối tượng gọi. Siêu đơn giản.

Câu trả lời phi công nghệ là có thể hoán đổi một động cơ trong xe ngay trước khi bạn bật nó lên. Nếu tất cả mọi thứ móc lên phải (giao diện), bạn là tốt.


34
2017-09-19 02:54