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


1826

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

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

292
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. Container là gì? Nghịch đảo? Phụ thuộc? Giải thích nó trong điều khoản cư sĩ mà không có những từ lớn.
kirk.burleson


8
Đó là Tiêm phụ thuộc (DI) - xem phần suy giảm của Martin Fowlers tại đây: martinfowler.com/articles/injection.html#InversionOfControl
Ricardo Sanchez


Nó là một tính từ, không phải danh từ, nó không phải là một thứ, nó là một mô tả về một sự thay đổi được thực hiện cho mã, trong đó sự kiểm soát dòng chảy nằm trong đại biểu, không phải là container.
Martin Spamer

Câu trả lời:


1523

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 khỏi 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ư thế này:

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 một sự phụ thuộc giữa TextEditorSpellChecker. Thay vào đó, trong kịch bản IoC, chúng ta sẽ làm một cái gì đó như thế này:

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à TextEditorlớp trực tiếp phụ thuộc vào SpellCheckerlớp.

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

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

Bây giờ ứng dụng khách tạo TextEditorlớp có quyền kiểm soát SpellCheckerviệc sử dụng triển khai nào vì chúng ta sẽ thêm phụ thuộc vào TextEditorchữ ký.


50
Tốt ví dụ rõ ràng. Tuy nhiên, giả sử thay vì yêu cầu giao diện ISpellChecker được chuyển đến hàm tạo của đối tượng, chúng tôi đã hiển thị nó dưới dạng một thuộc tính có thể thiết lập (hoặc phương thức SetSpellChecker). Điều này vẫn sẽ tạo thành IoC?
devios1

25
chainguy1337 - vâng. Sử dụng setters như thế được gọi là tiêm setter trái ngược với tiêm xây dựng (cả hai kỹ thuật tiêm phụ thuộc). IoC là một mô hình khá chung chung, nhưng tiêm chích phụ thuộc đạt được IoC
Jack Ukleja

257
Mặc dù có nhiều lượt bình chọn, câu trả lời này không chính xác. Vui lòng xem martinfowler.com/articles/injection.html#InversionOfControl . Cụ thể, lưu ý phần "Inversion of Control là một thuật ngữ quá chung chung, và do đó mọi người thấy nó khó hiểu. Kết quả là có rất nhiều cuộc thảo luận với những người ủng hộ IoC khác nhau, chúng tôi đã giải quyết cái tên Dependency Injection".
Rogério

45
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 về số lượng phiếu bầu tăng lên ;-)
Aravind Yarram

31
Tôi bên cạnh @Rogerio và @Pangea. Đây có thể là một ví dụ tốt cho tiêm xây dựng nhưng không phải là một câu trả lời tốt cho câu hỏi ban đầu. IoC, như được định nghĩa bởi Fowler , có thể được nhận ra 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 công cụ định vị dịch vụ hoặc thậm chí là kế thừa đơn giản.
mtsz

642

Inversion of Control là những gì bạn nhận được khi gọi lại chương trình, ví dụ như chương trình gui.

Ví dụ: trong thực đơn 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

từ đó 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 một thứ tự cố định, người dùng sẽ kiểm soát thứ tự nhập dữ liệu và khi dữ liệu được lưu trong cơ sở dữ liệu.

Về cơ bản, bất cứ điều gì có vòng lặp sự kiện, cuộc gọi lại hoặc kích hoạt thực thi đều thuộc loại này.


161
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 bị "đảo ngược" bởi việc tiêm phụ thuộc vì bạn đã ủy thác hiệu quả các phụ thuộc vào một số hệ thống bên ngoài (ví dụ: container IoC)
Jack Ukleja

38
Đồng ý với nhận xét của Schneider. 5 điểm hạ gục? Kính râm, vì đây là câu trả lời duy nhất thực sự đúng. Lưu ý phần mở đầu: ' giống như một chương trình gui.' Việc tiêm phụ thuộc chỉ là sự hiện thực hóa thường thấy nhất của IoC.
Jeff Sternal

40
Thật vậy, đây là một trong số ít các anwsers chính xác ! Các bạn, IoC không cơ bản về sự phụ thuộc. Không có gì.
Rogério

13
+1 - Đây là một mô tả hay (ví dụ) về tuyên bố sau của Martin Fowler - "Giao diện người dùng sớm được điều khiển 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ỉ "; chương trình sẽ điều khiển các lời nhắc và nhận phản hồi cho từng người. Với các UI đồ 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à thay vào đó chương trình của bạn cung cấp các 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 từ bạn sang khuôn khổ. "
Ashish Gupta

14
Bây giờ tôi hiểu lý do tại sao đôi khi nó được gọi một cách vô tình là "Nguyên tắc Hollywood: Đừng gọi cho chúng tôi, chúng tôi sẽ gọi cho bạn"
Alexander Suraphel

419

Đả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 điều khiển:

  1. Tách -to-làm phần việc từ khi -to-làm phần.
  2. Đảm bảo rằng khi một phần biết như ít càng tốt về những gì một 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.

-

Phần đảo ngược 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 từ đó!

-

Ví dụ

  • Xử lý sự kiện. Trình xử lý sự kiện (phần việc cần làm) - Sự kiện nâng cao (phần việc cần làm)
  • Giao diện. Thành phần máy khách (phần khi cần làm) - Thực hiện Giao diện thành phần (phần cần làm)
  • xUnit cố định. Thiết lập và TearDown (phần phải làm) - khung xUnit gọi đến Cài đặt ở đầu và TearDown ở cuối (phần khi cần làm)
  • Mẫu phương pháp thiết kế mẫu. phương thức mẫu khi phần việc cần làm - thực hiện lớp con nguyên thủy phần việc cần làm
  • Các phương thức chứa DLL trong COM. DLLMain, DLLCanUnload, v.v (phần phải làm) - COM / OS (phần khi cần làm)

Làm thế nào bạn đang nói Giao diện. Thành phần máy khách (phần khi cần làm) là "khi" không có ý nghĩa khi chúng tôi sử dụng giao diện (Ví dụ: Dependency Injection), chúng tôi chỉ tóm tắt nó và cung cấp cho khách hàng sự linh hoạt về việc thêm bất kỳ triển khai nào nhưng không có "khi nào" tham gia ở đó. Tôi đồng ý với "khi nào" trong trường hợp nâng cao sự kiện xử lý sự kiện.
OldSchool

Theo '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 'việc cần làm' cho dù ý định 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 chỉ ra cách các giao diện tạo ra phần cơ bản của đảo ngược điều khiển: martinfowler.com/articles/injection.html#InversionOfControl
rpattabi

Hai câu đầu tiên thật xuất sắc. tuyệt vời !! tách biệt hoàn hảo bởi khi nào nên làm và phải 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 nhiều sự ủng hộ như vậy. họ chỉ nói chuyện mã mà không có sự hiểu biết.
Amir Ziarati

2
Tôi thích lời giải thích what-to-dowhen-to-do
KimchiMan

164

Đảo ngược điều khiển là về việc 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 và bạn vô tình làm vỡ màn hình. Và chết tiệt, bạn tìm thấy màn hình máy tính xách tay mô hình tương tự không có 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 và bạn vô tình làm vỡ màn hình. Bạn thấy rằng bạn có thể lấy hầu hết mọi 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 để bàn 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 khác nhau, trong khi máy tính xách tay thì không, nó cần một màn hình cụ thể để sửa.


1
@Luo Jiong Hui Giải thích hay.
Sachin

3
Hầu hết các mẫu Thiết kế, nếu không phải là tất cả, có các đối tác của chúng trong cuộc sống hàng ngày mà chúng ta thấy và hiểu rất rõ. Cách hiệu quả nhất để hiểu 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

6
Câu trả lời không chính xác. Bạn đang giải thích tiêm phụ thuộc và không phải IoC. Xem bình luận của Rogério về câu trả lời này ở trên
MickyD

2
Tôi đồng ý. Đây là DI, không phải IoC. Vẫn nhận được một upvote từ, bởi vì nó là một cách tiếp cận đơn giản, nhưng giúp mở rộng sự hiểu biết về chủ đề này.
Mär

Nó giải thích tiêm phụ thuộc. Không phải Ioc. Nhưng giải thích tốt đẹp và rõ ràng.
Chamin Wickramarathna

120

Inversion of Control, (hay IoC), là về tự do (Bạn kết hôn, bạn mất tự do và bạn đang bị kiểm soát. Bạn đã ly dị, bạn vừa thực hiện Inversion of Control. Đó là những gì chúng tôi gọi là "tách rời". không khuyến khích một số 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. linh hoạt lựa chọn nước máy hoặc cà phê.) 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 tài chính vào đối tác của mình, do đó bạn bị 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áy tính để bàn, bạn đã trượt (hoặc nói, được 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 để gõ và sử dụng chuột để điều hướng. Và một phần mềm được viết xấu có thể làm nô lệ bạn nhiều hơn. Nếu bạn thay thế máy tính để bàn của bạn bằng một máy tính xách tay, thì bạn phần nào đảo ngược đ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 bạn đang ở đâu 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 triển khai Inversion of Control, người tiêu dùng phần mềm / đối tượng nhận đượ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 đầu. Chúng tôi vẫn bỏ lỡ 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 khung tinh vi. Đ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 chế tạo 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ụ (khung phần mềm) để chế tạo xe. Một khung phần mềm truyền thống 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 phải tự lên 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 hơi không phải là một công việc 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 đắn. Một hiện đạikhung phần mềm sẽ giống như một nhà máy ô tô hiện đại với tất cả các cơ sở và nhà quản lý tại chỗ. Các công nhân không phải lập bất kỳ kế hoạch nào, các nhà quản lý (một phần của khung, họ là những người thông minh nhất và thực hiện kế hoạch tinh vi nhất) sẽ giúp phối hợp để công nhân biết khi nào thực hiện công việc của họ (khung gọi mã của bạn). Các công nhân 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 Dependency Injection).

Mặc dù các công nhân trao quyền kiểm soát quản lý dự án ở cấp cao nhất cho các nhà quản lý (khuôn khổ). 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 để thực hiện Định tuyến URL và đặt Bộ điều khiển thay thế cho khung để gọi.

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


21
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

"Mặc dù các công nhân trao quyền kiểm soát quản lý dự án ở cấp cao nhất cho các nhà quản lý (khung). Nhưng thật tốt khi có một số chuyên gia giúp đỡ. Đây là khái niệm về IoC thực sự đến từ." - Đầu tiên, sự kiểm soát là với người quản lý. Bạn có thể giải thích làm thế nào điều khiển được đảo ngược? Với sự giúp đỡ của các chuyên gia (loại chuyên nghiệp)? Làm sao ?
Istiaque Ahmed

@Istiaque Ahmed, so với một nhà để xe nơi công nhân có toàn quyền kiểm soát mọi thứ, các nhà quản lý trong nhà máy ô tô hiện đại kiểm soát việc sản xuất. Vì vậy, bây giờ công nhân được kiểm soát thay vì kiểm soát. Hãy lưu ý, các nhà quản lý trong bối cảnh này là một phần của nhà máy ô tô hiện đại, không phải là một phần của công nhân. Chuyên gia là những người quản lý chuyên nghiệp trong việc lập kế hoạch và sản xuất xe hơi.
Luo Jiong Hui

2
Thông điệp cho những người đã kết hôn: đừng ly hôn ngay bây giờ, các lớp con của bạn cũng có thể triển khai IoC.
Julian

Vâng, đây chỉ là tầm nhìn của tôi về hôn nhân cũng là IoC
balron

94

Trước khi sử dụng Inversion of Control, bạn nên nhận thức rõ thực tế rằng nó có những ưu và nhược điểm và bạn nên biết lý do 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 các triển khai của 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
  • Rất dễ dàng để viết các bài kiểm tra đơn vị cho mã của bạn bởi vì nó phụ thuộc vào không gì khác ngoài các đối tượng mà nó chấp nhận trong hàm tạo / 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 phù hợp.

Nhược điểm:

  • IoC không chỉ đảo ngược luồng điều khiển trong chương trình của bạn, mà còn làm mờ đi đá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 bởi vì các kết nối thường có 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 hoặc chú thích XML và trong mã của bộ chứa IoC của bạn diễn giải các siêu dữ liệu này.
  • Có một loại lỗi mới trong đó bạn nhận được cấu hình XML hoặc các chú thích của bạn sai và bạn có thể dành nhiều thời gian để tìm hiểu lý do tại sao bộ chứa 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 một số điều kiện nhất định.

Cá nhân tôi thấy những đ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ể 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 tạo thành chương trình "thực" mà chỉ là thứ cần được kết hợp bởi Cấu hình hoặc siêu dữ liệu chú thích và sẽ tách ra (và giảm) nếu không có nó.


3
Con đầu tiên không chính xác. Tốt nhất chỉ nên có 1 lần sử dụng bộ chứa IOC trong mã của bạn và đó là phương thức chính của bạn. Mọi thứ khác sẽ đổ xuống từ đó
mwjackson

23
Tôi nghĩ ý của anh ấy là, bạn không thể đọc: myService.DoSthing () và đi đến định nghĩa của DoSthing, bởi vì với IoC, myService chỉ là một giao diện và bạn không biết triển khai thực tế, trừ khi bạn đi tìm nó lên trong tập tin cấu hình xml hoặc phương thức chính nơi ioc của bạn được thiết lập.
chrismay

7
Đó là nơi Resharper giúp - "nhấp vào thực hiện" đối với giao diện. Tránh IoC (hay cụ thể hơn là DI từ ví dụ của bạn) có lẽ cũng có nghĩa là bạn không kiểm tra đúng cách
IThasTheAnswer

10
Re: 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 tạo thành một chương trình "thực" mà chỉ là thứ gì đó cần được kết hợp bởi siêu dữ liệu cấu hình hoặc chú thích XML và sẽ sụp đổ mà không có nó - tôi nghĩ điều này là rất sai lệch. Điều tương tự cũng có thể được nói về bất kỳ chương trình nào được viết trên đỉnh của một khung. Sự khác biệt với bộ chứa IoC tốt là bạn sẽ có thể, nếu chương trình của bạn được thiết kế và viết tốt, hãy lấy nó ra và đặt vào một cái khác với các thay đổi tối thiểu cho mã của bạn, hoặc ném hoàn toàn IoC và xây dựng các đối tượng của bạn bằng tay .
Gấu Awnry

7
Thật tốt khi thấy một 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ế hướng đối tượng và thực hành TDD, đã sử dụng giao diện, mô hình nhà máy, mô hình hướng sự kiện và chế giễu, điều đó có ý nghĩa, trước khi từ thông dụng "IoC" này được phát minh. Thật không may, quá nhiều nhà phát triển / "kiến trúc sư" yêu cầu thực hành xấu nếu bạn không sử dụng các khung công tác ưa thích của họ. Tôi thích một thiết kế tốt hơn, sử dụng các khái niệm và công cụ ngôn ngữ tích hợp, để đạt được cùng một mục tiêu với một phần phức tạp, tức là không "làm phiền" việc triển khai như bạn nói :-)
Tony Wall

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

  2. Nó giải quyết sao chép mã. Ví dụ, ngày xưa bạn sẽ tự viết vòng lặp sự kiện của riêng mình, 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 với các thư viện hệ thống về những sự kiện 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 điều khiển là một cách thực tế để giảm trùng lặp mã và nếu bạn thấy mình sao chép toàn bộ một phương thức và chỉ thay đổi một đoạn mã nhỏ, bạn có thể xem xét xử lý nó bằng đảo ngược điều khiển. Đảo ngược điều khiển được thực hiện dễ dàng trong nhiều ngôn ngữ thông qua khái niệm đại biểu, giao diện hoặc thậm chí con trỏ hàm 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ó theo dõi hơn khi được viết theo cách này. Đây là một cách hữu ích để thiết kế các phương thức khi viết thư viện sẽ được sử dụng lại, nhưng nó nên được sử dụng một cách tiết kiệm trong cốt lõi của chương trình của bạn trừ khi nó thực sự giải quyết được vấn đề sao chép mã.


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

Viết vòng lặp sự kiện của riêng bạn vẫn có thể đảo ngược điều khiển, nếu vòng lặp sự kiện đó thay thế một khung công tác và phần còn lại của mã đang sử dụng nguyên tắc IoC bạn vừa viết khung công tác của riêng bạn. Đây thực sự không phải là một điều xấu, nó làm tăng khả năng đọc với mức giá chỉ hơn một chút mã hóa (không phải nó luôn luôn phù hợp).
lijat

45

Nhưng tôi nghĩ bạn phải rất cẩn thận với nó. Nếu bạn quá lạm dụng mẫu này, bạn sẽ tạo ra 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 thì có lẽ không thực sự cần thiết phải sử dụng IoC? Trừ khi bạn cần viết bài kiểm tra đơn vị hoặc một cái gì đó ...

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


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

@Trace Bạn có thể biết chương trình bạn sẽ viết sẽ được sử dụng như thế nào chẳng hạn. Vẫn còn một số kỹ thuật như tiêm phụ thuộc rẻ đến mức hiếm khi có lý do để không sử dụng chúng trong trường hợp như thế này.
lijat

44

IoC / DI với tôi đang đẩy ra sự 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ể trao đổi một động cơ trong xe hơi ngay trước khi bạn bật nó lên. Nếu mọi thứ kết nối đúng (giao diện), bạn tốt.


44

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 được 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.


26
  1. Đảo ngược điều khiển là một mẫu được sử dụng để tách các thành phần và các lớp trong hệ thống. Các mô hình được thực hiện thông qua việc tiêm phụ thuộc vào một thành phần khi nó được xây dựng. Những sự phụ thuộc này thường được cung cấp như các giao diện để tiếp tục tách rời và để hỗ trợ khả năng kiểm tra. Các container IoC / DI như Castle Windsor, Unity là các công cụ (thư viện) có thể được sử dụng để cung cấp IoC. Các công cụ này cung cấp các tính năng mở rộng ở trên và ngoài quản lý phụ thuộc đơn giản, bao gồm trọn đời, AOP / Đánh chặn, chính sách, v.v.

  2. a. Làm giảm bớt một thành phần khỏi trách nhiệm quản lý các phụ thuộc của nó.
    b. Cung cấp khả năng hoán đổi việc thực hiện phụ thuộc trong các môi trường khác nhau.
    c. Cho phép một thành phần được kiểm tra thông qua chế độ phụ thuộc.
    d. Cung cấp một cơ chế để chia sẻ tài nguyên trong suốt một ứng dụng.

  3. a. Quan trọng khi làm phát triển dựa trên thử nghiệm. Không có IoC, có thể khó kiểm tra, vì các thành phần được thử nghiệm được kết hợp chặt chẽ với phần còn lại của hệ thống.
    b. Quan trọng khi phát triển hệ thống mô-đun. Một hệ thống mô-đun là một hệ thống có các thành phần có thể được thay thế mà không cần biên dịch lại.
    c. Quan trọng nếu có nhiều mối quan tâm xuyên suốt cần được giải quyết, một phần trong ứng dụng doanh nghiệp.


2
Trên thực tế, IoC không chủ yếu về quản lý các phụ thuộc. Vui lòng xem martinfowler.com/articles/injection.html#InversionOfControl Đặc biệt, lưu ý phần nói "Đảo ngược kiểm soát là một thuật ngữ quá chung chung và do đó mọi người thấy khó hiểu. Kết quả là có rất nhiều cuộc thảo luận với nhiều người ủng hộ IoC chúng tôi giải quyết tên phụ thuộc tiêm ".
Rogério

26

Chỉ trả lời phần đầu tiên. Nó là gì?

Inversion of Control (IoC) có nghĩa là tạo các thể hiện của các phụ thuộc trước và sau của một lớp (tùy ý tiêm chúng thông qua hàm tạo), thay vì tạo một thể hiện của lớp trước và sau đó là thể hiện của lớp phụ thuộc. Do đó, đảo ngược kiểm soát đảo ngược các dòng điều khiển của chương trình. Thay vì các callee kiểm soát các dòng điều khiển (trong khi tạo ra phụ thuộc), các người gọi kiểm soát dòng chảy của sự kiểm soát của chương trình .


Đây không phải là về tạo lớp hoặc đối tượng, hãy kiểm tra martinfowler.com/articles/injection.html#InversionOfControl
Raghvendra Singh

22

Tôi sẽ viết ra cách hiểu đơn giản của tôi về hai thuật ngữ này:

For quick understanding just read examples*

Dependency Injection (DI):
Nói chung phụ thuộc có nghĩa là truyền một đối tượng mà phương thức phụ thuộc, như một tham số cho một phương thức, thay vì phương thức tạo đối tượng phụ thuộc .
Điều đó có nghĩa là gì trong thực tế là phương pháp này không phụ thuộc trực tiếp vào việc thực hiện cụ thể; bất kỳ thực hiện nào đáp ứng các yêu cầu có thể được thông qua như một tham số.

Với đối tượng này nói phụ thuộc của họ. Và mùa xuân làm cho nó có sẵn.
Điều này dẫn đến sự phát triển ứng dụng kết hợp lỏng lẻo.

Quick Example:EMPLOYEE OBJECT WHEN CREATED,
              IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
   (if address is defines as dependency by Employee object)

Container đảo ngược điều khiển (IoC):
Đây là đặc điểm chung của các khung công tác, IOC quản lý các đối tượng java
- từ khởi tạo đến hủy diệt thông qua BeanFactory của nó.
-Các thành phần của Java được khởi tạo bởi bộ chứa IoC được gọi là các hạt và bộ chứa IoC quản lý phạm vi của một hạt, các sự kiện vòng đời và bất kỳ tính năng AOP nào được cấu hình và mã hóa.

QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it.

Bằng cách triển khai Inversion of Control, người tiêu dùng phần mềm / đối tượng có đượ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.

Đảo ngược điều khiển như một hướng dẫn thiết kế phục vụ các mục đích sau:

Có một sự tách rời của việc thực hiện một nhiệm vụ nhất định từ việc thực hiện.
Mỗi mô-đun có thể tập trung vào những gì nó được thiết kế cho.
Các mô-đun không đưa ra giả định về những gì các hệ thống khác làm mà chỉ dựa vào hợp đồng của họ.
Thay thế các mô-đun không có tác dụng phụ trên các mô-đun khác
Tôi sẽ giữ mọi thứ trừu tượng ở đây, Bạn có thể truy cập các liên kết sau để hiểu chi tiết về chủ đề này.
Đọc tốt với ví dụ

Giải thích chi tiết


17

Tôi đồng ý với NilObject , nhưng tôi muốn thêm vào điều này:

nếu bạn thấy mình sao chép toàn bộ một phương thức và chỉ thay đổi một đoạn mã nhỏ, bạn có thể xem xét việc giải quyết nó với sự đảo ngược của điều khiển

Nếu bạn thấy mình sao chép và dán mã xung quanh, bạn hầu như luôn làm sai điều gì đó . Được mã hóa theo nguyên tắc thiết kế Một lần và Chỉ một lần .


17

Ví dụ, nhiệm vụ # 1 là tạo đối tượng. Nếu không có khái niệm IOC, nhiệm vụ # 1 được cho là do Lập trình viên thực hiện. Nhưng với khái niệm IOC, nhiệm vụ # 1 sẽ được thực hiện bằng container.

Trong ngắn hạn, Control được chuyển từ Lập trình viên sang container. Vì vậy, nó được gọi là đảo ngược của kiểm soát.

Tôi tìm thấy một ví dụ tốt ở đây .


Container là một khái niệm trong IoC trong đó mô hình đối tượng, bao gồm các phụ thuộc (mối quan hệ giữa đối tượng "người dùng" và đối tượng "đã sử dụng") và các thể hiện đối tượng, cư trú và được quản lý - ví dụ: có chứa. Container thường được cung cấp bởi khung IoC, chẳng hạn như Spring. Hãy nghĩ về nó như một kho lưu trữ thời gian chạy cho các đối tượng tạo nên ứng dụng của bạn.
Gấu Awnry

17

Hãy nói rằng chúng tôi thực hiện một số cuộc họp trong một số khách sạn.

Nhiều người, nhiều bình nước, nhiều cốc nhựa.

Khi ai đó muốn uống, cô rót đầy cốc, uống và ném cốc xuống sàn.

Sau giờ hoặc một cái gì đó, chúng tôi có một sàn được phủ bằng cốc nhựa và nước.

Hãy đảo ngược điều khiển.

Cùng một cuộc họp ở cùng một nơi, nhưng thay vì ly nhựa, chúng tôi có một người phục vụ với một cốc thủy tinh (Singleton)

và cô ấy tất cả thời gian cung cấp cho khách uống.

Khi ai đó muốn uống, cô lấy từ ly bồi bàn, uống và trả lại cho người phục vụ.

Bỏ qua câu hỏi về vệ sinh, hình thức kiểm soát quá trình uống cuối cùng có hiệu quả và kinh tế hơn nhiều.

Và đây chính xác là những gì Spring (một container IoC khác, ví dụ: Guice) làm. Thay vì để ứng dụng tạo ra những gì nó cần bằng cách sử dụng từ khóa mới (lấy cốc nhựa), bộ chứa Spring IoC luôn luôn cung cấp cho ứng dụng cùng một ví dụ (singleton) của đối tượng cần thiết (ly nước).

Hãy nghĩ về bản thân bạn như là người tổ chức cuộc họp như vậy. Bạn cần cách để nhắn tin cho quản trị khách sạn

Gặp gỡ các thành viên sẽ cần ly nước nhưng không phải là miếng bánh.

Thí dụ:-

public class MeetingMember {

    private GlassOfWater glassOfWater;

    ...

    public void setGlassOfWater(GlassOfWater glassOfWater){
        this.glassOfWater = glassOfWater;
    }
    //your glassOfWater object initialized and ready to use...
    //spring IoC  called setGlassOfWater method itself in order to
    //offer to meetingMember glassOfWater instance

}

Liên kết hữu ích:-


không phải là đối tượng loại tĩnh?
Gokigooooks

16

Có vẻ như điều khó hiểu nhất về "IoC" từ viết tắt và tên của nó là nó quá quyến rũ của một cái tên - gần như là một tên tiếng ồn.

Chúng ta có thực sự cần một cái tên để mô tả sự khác biệt giữa lập trình hướng đến thủ tục và sự kiện không? OK, nếu chúng ta cần, nhưng chúng ta có cần chọn một cái tên hoàn toàn mới "lớn hơn cuộc sống" gây nhầm lẫn nhiều hơn nó không?


1
IoC! = Sự kiện thúc đẩy. Điểm tương đồng (và trong một số trường hợp chồng chéo), nhưng về cơ bản chúng không giống nhau.
Gấu Awnry

Câu hỏi hay. Lập trình hướng sự kiện IS chắc chắn là IoC. Chúng tôi viết các trình xử lý sự kiện và chúng được gọi từ vòng lặp sự kiện. Nhưng, IoC là khái niệm chung chung hơn so với lập trình hướng sự kiện .. Nếu bạn ghi đè một phương thức trong lớp con, thì đó cũng là một loại IoC. Bạn viết một mã sẽ được gọi khi tham chiếu (ví dụ) thích hợp được sử dụng.
vi.su.

15

Đảo ngược kiểm soát là khi bạn đến cửa hàng tạp hóa và vợ bạn đưa cho bạn danh sách các sản phẩm cần mua.

Trong thuật ngữ lập trình, cô đã chuyển một hàm gọi lại getProductList()cho hàm bạn đang thực thi - doShopping().

Nó cho phép người dùng chức năng xác định một số phần của nó, làm cho nó linh hoạt hơn.


5
Vợ tôi thường mua sắm với tôi, nhưng tôi đồng ý với tuyên bố này.
ha9u63ar

1
@ ha9u63ar Vợ bạn mua sắm với bạn? Vâng, đó được gọi là tổng hợp sau đó.
Julian

2
Nếu cô ấy cũng đưa tiền, nó được gọi là DI.
San

1
Từ Inversion - lộn ngược - xuất phát từ, khi vợ getProductList()bạn gọi bạn phải tìm nguồn tiền, có nghĩa là sự kiểm soát đang ở bên bạn. Trong trường hợp đảo ngược, cô ấy sẽ kiểm soát, có nghĩa là tiền cô ấy cũng sẽ cung cấp để mua.
San

13

Tôi đã tìm thấy một ví dụ rất rõ ràng ở đây giải thích cách 'điều khiển bị đảo ngược'.

Mã cổ điển (không cần tiêm phụ thuộc)

Đây là cách một mã không sử dụng DI sẽ hoạt động đại khái:

  • Ứng dụng cần Foo (ví dụ: bộ điều khiển), vì vậy:
  • Ứng dụng tạo Foo
  • Ứng dụng gọi Foo
    • Foo cần Bar (ví dụ: một dịch vụ), vì vậy:
    • Foo tạo Bar
    • Foo gọi cho Bar
      • Thanh cần Bim (một dịch vụ, một kho lưu trữ, trên mạng), vì vậy:
      • Bar tạo ra Bim
      • Bar làm một cái gì đó

Sử dụng tiêm phụ thuộc

Đây là cách một mã sử dụng DI sẽ hoạt động thô:

  • Ứng dụng cần Foo, cần Bar, cần Bim, vì vậy:
  • Ứng dụng tạo Bim
  • Ứng dụng tạo Bar và cung cấp cho nó Bim
  • Ứng dụng tạo Foo và cung cấp cho nó Bar
  • Ứng dụng gọi Foo
    • Foo gọi cho Bar
      • Bar làm một cái gì đó

Sự kiểm soát của các phụ thuộc được đảo ngược từ một người được gọi sang một người gọi.

Nó giải quyết vấn đề gì?

Phụ thuộc tiêm giúp dễ dàng trao đổi với việc thực hiện khác nhau của các lớp được tiêm. Trong khi kiểm tra đơn vị, bạn có thể thực hiện một triển khai giả, điều này làm cho việc kiểm tra dễ dàng hơn rất nhiều.

Ví dụ: Giả sử ứng dụng của bạn lưu trữ tệp người dùng đã tải lên trong Google Drive, với DI mã điều khiển của bạn có thể trông như thế này:

class SomeController
{
    private $storage;

    function __construct(StorageServiceInterface $storage)
    {
        $this->storage = $storage;
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

class GoogleDriveService implements StorageServiceInterface
{
    public function authenticate($user) {}
    public function putFile($file) {}
    public function getFile($file) {}
}

Khi yêu cầu của bạn thay đổi, thay vì GoogleDrive, bạn được yêu cầu sử dụng Dropbox. Bạn chỉ cần viết một triển khai dropbox cho StorageServiceInterface. Bạn không thực hiện bất kỳ thay đổi nào trong bộ điều khiển miễn là việc triển khai Dropbox tuân thủ StorageServiceInterface.

Trong khi kiểm tra, bạn có thể tạo bản giả cho StorageServiceInterface bằng cách triển khai giả trong đó tất cả các phương thức trả về null (hoặc bất kỳ giá trị được xác định trước nào theo yêu cầu thử nghiệm của bạn).

Thay vào đó, nếu bạn có lớp trình điều khiển để xây dựng đối tượng lưu trữ với newtừ khóa như thế này:

class SomeController
{
    private $storage;

    function __construct()
    {
        $this->storage = new GoogleDriveService();
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

Khi bạn muốn thay đổi với triển khai Dropbox, bạn phải thay thế tất cả các dòng nơi newđối tượng GoogleDriveService được xây dựng và sử dụng DropboxService. Bên cạnh đó khi kiểm tra lớp someContoder, hàm tạo luôn mong đợi lớp GoogleDriveService và các phương thức thực tế của lớp này được kích hoạt.

Khi nào thì thích hợp và khi nào thì không? Theo tôi, bạn sử dụng DI khi bạn nghĩ rằng có (hoặc có thể) các triển khai thay thế của một lớp.


Đây phải là câu trả lời đúng nhất vì nó là câu trả lời duy nhất giải thích cách "điều khiển" được đảo ngược.
Yarimadam

giải thích tốt nhất cho đến nay
Ali80

12

Một lời giải thích bằng văn bản rất đơn giản có thể được tìm thấy ở đây

http://binstock.blogspot.in/2008/01/excellence-explanation-of-dependency.html

Nó nói rằng -

"Bất kỳ ứng dụng không cần thiết nào cũng được tạo thành từ hai hoặc nhiều lớp cộng tác với nhau để thực hiện một số logic nghiệp vụ. Theo truyền thống, mỗi đối tượng chịu trách nhiệm lấy các tham chiếu riêng của mình đến các đối tượng mà nó cộng tác (phụ thuộc vào nó). các đối tượng được cung cấp các phụ thuộc của chúng tại thời điểm tạo bởi một số thực thể bên ngoài điều phối từng đối tượng trong hệ thống. Nói cách khác, các phụ thuộc được đưa vào các đối tượng. "


12

Inversion of Control là một nguyên tắc chung, trong khi Dependency Injection thực hiện nguyên tắc này như một mẫu thiết kế để xây dựng biểu đồ đối tượng (nghĩa là cấu hình kiểm soát cách các đối tượng đang tham chiếu lẫn nhau, thay vì chính đối tượng điều khiển cách lấy tham chiếu đến đối tượng khác).

Nhìn vào Inversion of Control như một mẫu thiết kế, chúng ta cần nhìn vào những gì chúng ta đang đảo ngược. Dependency Injection đảo ngược điều khiển xây dựng đồ thị của các đối tượng. Nếu được nói theo thuật ngữ của giáo dân, việc đảo ngược kiểm soát ngụ ý sự thay đổi trong dòng kiểm soát trong chương trình. Ví dụ. Trong ứng dụng độc lập truyền thống, chúng tôi có phương thức chính, từ đó quyền điều khiển được chuyển đến các thư viện bên thứ ba khác (trong trường hợp, chúng tôi đã sử dụng chức năng của thư viện bên thứ ba), nhưng thông qua điều khiển đảo ngược được chuyển từ mã thư viện của bên thứ ba sang mã của chúng tôi , như chúng tôi đang sử dụng dịch vụ của thư viện bên thứ ba. Nhưng có những khía cạnh khác cần được đảo ngược trong một chương trình - ví dụ như gọi các phương thức và luồng để thực thi mã.

Đối với những người quan tâm sâu hơn về Inversion of Control, một bài báo đã được xuất bản phác thảo một bức tranh hoàn chỉnh hơn về Inversion of Control dưới dạng mẫu thiết kế (OfficeFloor: sử dụng các mẫu văn phòng để cải thiện thiết kế phần mềm http://doi.acm.org/10.1145/ 2739011.2739013 với một bản sao miễn phí có sẵn để tải xuống từ http://www.officefloor.net/about.html ).

Những gì được xác định là mối quan hệ sau đây:

Inversion of Control (đối với phương thức) = Dependency (state) Tiêm + Tiêm liên tục + Tiêm chỉ

Tóm tắt về mối quan hệ trên đối với Đảo ngược kiểm soát có sẵn - http://dzone.com/articles/inversion-of-coupling-control


Đây là một câu trả lời rất rõ ràng. Cảm ơn đã giải thích.
KunYu Tsai

11

IoC là về việc đảo ngược mối quan hệ giữa mã của bạn và mã của bên thứ ba (thư viện / khung):

  • Trong phát triển s / w bình thường, bạn viết phương thức main () và gọi các phương thức "library". Bạn đang kiểm soát :)
  • Trong IoC, "khung" điều khiển hàm main () và gọi các phương thức của bạn. Các khung là trong kiểm soát :(

DI (Dependency Injection) là về cách điều khiển chảy trong ứng dụng. Ứng dụng máy tính để bàn truyền thống có luồng điều khiển từ ứng dụng (phương thức chính ()) của bạn đến các cuộc gọi phương thức thư viện khác, nhưng với luồng điều khiển DI bị đảo ngược, khung đó sẽ đảm nhiệm việc khởi động ứng dụng của bạn, khởi tạo ứng dụng và gọi phương thức của bạn bất cứ khi nào cần.

Cuối cùng bạn luôn thắng :)


10

Tôi thích cách giải thích này: http://joelabrahamsson.com/inversion-of-control-an-int sinhtion-with-exples-in-net /

Nó bắt đầu đơn giản và hiển thị các ví dụ mã là tốt.

nhập mô tả hình ảnh ở đây

Người tiêu dùng, X, cần lớp tiêu thụ, Y, để hoàn thành một cái gì đó. Đó là tất cả tốt và tự nhiên, nhưng X thực sự cần phải biết rằng nó sử dụng Y?

Không đủ để X biết rằng nó sử dụng thứ gì đó có hành vi, phương thức, tính chất, v.v. của Y mà không biết ai thực sự thực hiện hành vi đó?

Bằng cách trích xuất một định nghĩa trừu tượng về hành vi được sử dụng bởi X trong Y, được minh họa như tôi bên dưới và để người tiêu dùng X sử dụng một thể hiện của điều đó thay vì Y, họ có thể tiếp tục làm những gì nó làm mà không cần phải biết cụ thể về Y.

nhập mô tả hình ảnh ở đây

Trong hình minh họa ở trên, Y thực hiện I và X sử dụng một ví dụ của I. Mặc dù X vẫn có thể sử dụng Y nhưng điều thú vị là X không biết điều đó. Nó chỉ biết rằng nó sử dụng một cái gì đó thực hiện I.

Đọc bài viết để biết thêm thông tin và mô tả về các lợi ích như:

  • X không phụ thuộc vào Y nữa
  • Linh hoạt hơn, việc thực hiện có thể được quyết định trong thời gian chạy
  • Cách ly đơn vị mã, kiểm tra dễ dàng hơn

...


Các liên kết là rất hữu ích. Thực sự cảm ơn :)
M Fuat NUROĞLU 18/07/19

10

Tôi hiểu rằng câu trả lời đã được đưa ra ở đây. Nhưng tôi vẫn nghĩ rằng, một số điều cơ bản về sự đảo ngược của kiểm soát phải được thảo luận ở đây cho các độc giả tương lai.

Inversion of Control (IoC) đã được xây dựng trên một nguyên tắc rất đơn giản gọi là Nguyên tắc Hollywood . Và nó nói rằng,

Đừng gọi cho chúng tôi, chúng tôi sẽ gọi cho bạn

Điều đó có nghĩa là đừng đến Hollywood để thực hiện ước mơ của bạn thay vì nếu bạn xứng đáng thì Hollywood sẽ tìm thấy bạn và biến giấc mơ của bạn thành hiện thực. Khá nhiều đảo ngược, phải không?

Bây giờ khi chúng ta thảo luận về nguyên tắc của IoC, chúng ta sử dụng để quên đi Hollywood. Đối với IoC, phải có ba yếu tố, một Hollywood, bạn và một nhiệm vụ muốn thực hiện ước mơ của bạn.

Trong thế giới lập trình của chúng tôi, Hollywood đại diện cho một khung chung (có thể được viết bởi bạn hoặc người khác), bạn đại diện cho mã người dùng bạn đã viết và tác vụ đại diện cho điều bạn muốn thực hiện với mã của mình. Bây giờ bạn không bao giờ tự mình kích hoạt nhiệm vụ của mình, không phải trong IoC! Thay vào đó, bạn đã thiết kế mọi thứ sao cho khung của bạn sẽ kích hoạt nhiệm vụ cho bạn. Do đó, bạn đã xây dựng một khuôn khổ có thể tái sử dụng, có thể biến ai đó thành anh hùng hoặc người khác trở thành kẻ xấu. Nhưng khuôn khổ đó luôn luôn có trách nhiệm, nó biết khi nào nên chọn ai đó và ai đó chỉ biết những gì nó muốn trở thành.

Một ví dụ thực tế cuộc sống sẽ được đưa ra ở đây. Giả sử, bạn muốn phát triển một ứng dụng web. Vì vậy, bạn tạo một khung công tác sẽ xử lý tất cả những điều phổ biến mà ứng dụng web sẽ xử lý như xử lý yêu cầu http, tạo menu ứng dụng, phục vụ trang, quản lý cookie, kích hoạt sự kiện, v.v.

Và sau đó, bạn để lại một số móc trong khung của mình, nơi bạn có thể đặt thêm mã để tạo menu tùy chỉnh, trang, cookie hoặc ghi nhật ký một số sự kiện của người dùng, v.v ... Trên mỗi yêu cầu trình duyệt, khung của bạn sẽ chạy và thực thi mã tùy chỉnh của bạn nếu được nối lại vào trình duyệt.

Vì vậy, ý tưởng là khá nhiều đơn giản. Thay vì tạo một ứng dụng người dùng sẽ kiểm soát mọi thứ, trước tiên, bạn tạo một khung có thể sử dụng lại, nó sẽ kiểm soát mọi thứ sau đó viết mã tùy chỉnh của bạn và móc nó vào khung để thực hiện kịp thời.

Laravel và EJB là những ví dụ về các khung như vậy.

Tài liệu tham khảo:

https://martinfowler.com/bliki/InversionOfControl.html

https://en.wikipedia.org/wiki/Inversion_of_control


1
Câu trả lời thích hợp nhất tôi tìm thấy ở đây.
xanh

8

Lập trình nói

IoC dễ hiểu: Đó là việc sử dụng Giao diện như một cách cụ thể (một trường hoặc tham số) như một ký tự đại diện có thể được sử dụng bởi một số lớp. Nó cho phép tái sử dụng mã.

Ví dụ: giả sử chúng ta có hai lớp: ChóMèo . Cả hai đều có chung phẩm chất / trạng thái: tuổi, kích thước, cân nặng. Vì vậy, thay vì tạo ra một lớp dịch vụ được gọi là DogServiceCatService , tôi có thể tạo một lớp duy nhất gọi là AnimalService chỉ cho phép sử dụng Dog và Cat nếu chúng sử dụng giao diện IAnimal .

Tuy nhiên, thực tế mà nói, nó có một số ngược.

a) Hầu hết các nhà phát triển không biết cách sử dụng nó . Ví dụ, tôi có thể tạo một lớp được gọi là Khách hàngtôi có thể tạo tự động (sử dụng các công cụ của IDE) một giao diện có tên là ICustomer . Vì vậy, không hiếm khi tìm thấy một thư mục chứa đầy các lớp và giao diện, bất kể các giao diện đó có được sử dụng lại hay không. Nó được gọi là BLOATED. Một số người có thể lập luận rằng "có thể trong tương lai chúng ta có thể sử dụng nó". : - |

b) Nó có một số hạn chế. Ví dụ: hãy nói về trường hợp của ChóMèo và tôi muốn thêm một dịch vụ mới (chức năng) chỉ dành cho chó. Giả sử tôi muốn tính số ngày tôi cần huấn luyện một con chó ( trainDays()), đối với mèo thì vô dụng, mèo không thể được huấn luyện (tôi nói đùa).

b.1) Nếu tôi thêm trainDays() vào Dịch vụ AnimalService thì nó cũng hoạt động với mèo và nó hoàn toàn không hợp lệ.

b.2) Tôi có thể thêm một điều kiện trong trainDays()đó nó đánh giá lớp nào được sử dụng. Nhưng nó sẽ phá vỡ hoàn toàn IoC.

b.3) Tôi có thể tạo một lớp dịch vụ mới gọi là DogService chỉ cho chức năng mới. Nhưng, nó sẽ tăng khả năng duy trì mã bởi vì chúng tôi sẽ có hai lớp dịch vụ (có chức năng tương tự) cho Dog và điều đó thật tệ.


Về các lớp / giao diện cồng kềnh: Bạn không phải luôn luôn sử dụng lại mọi giao diện. Đôi khi, thật hợp lý khi chia một giao diện lớn thành nhiều phần nhỏ hơn để xem ranh giới chức năng của nó. Các giao diện nhỏ hơn cũng dễ dàng sử dụng lại trong các triển khai khác. Ngoài ra, nó khuyến khích bạn mã hóa một giao diện bất cứ nơi nào nó có ý nghĩa. Xem xét "Phân chia giao diện". Chỉ bởi vì bạn đang sử dụng một giao diện không có nghĩa là bạn bị tách rời. Một giao diện chất béo duy nhất là vô dụng. - Chỉ 2 xu của tôi :)
MK

7

Tôi đã đọc rất nhiều câu trả lời cho vấn đề này nhưng nếu ai đó vẫn còn bối rối và cần một "thuật ngữ layman" cực kỳ cao để giải thích IoC thì đây là:

Hãy tưởng tượng một phụ huynh và trẻ em nói chuyện với nhau.

Không có IoC:

* Phụ huynh : Bạn chỉ có thể nói khi tôi đặt câu hỏi cho bạn và bạn chỉ có thể hành động khi tôi cho phép bạn.

Phụ huynh : Điều này có nghĩa là, bạn không thể hỏi tôi nếu bạn có thể ăn, chơi, đi vệ sinh hay thậm chí ngủ nếu tôi không hỏi bạn.

Phụ huynh : Bạn có muốn ăn không?

Đứa trẻ : Không.

Phụ huynh : Được rồi, tôi sẽ trở lại. Chờ tôi.

Trẻ em : (Muốn chơi nhưng vì không có câu hỏi nào từ cha mẹ, nên trẻ không thể làm gì được).

Sau 1 giờ ...

Phụ huynh : Tôi đã trở lại. Bạn muốn chơi không?

Con : Vâng.

Phụ huynh : Được phép.

Đứa trẻ : (cuối cùng cũng có thể chơi).

Kịch bản đơn giản này giải thích điều khiển được tập trung vào cha mẹ. Tự do của trẻ bị hạn chế và phụ thuộc nhiều vào câu hỏi của cha mẹ. Đứa trẻ CHỈ có thể nói khi được yêu cầu nói, và CHỈ có thể hành động khi được phép.

Với IoC:

Bây giờ trẻ có khả năng đặt câu hỏi và phụ huynh có thể trả lời bằng câu trả lời và quyền. Đơn giản có nghĩa là sự kiểm soát bị đảo ngược! Đứa trẻ bây giờ có thể tự do đặt câu hỏi bất cứ lúc nào và mặc dù vẫn còn sự phụ thuộc với cha mẹ về các quyền, nhưng nó không phụ thuộc vào phương tiện nói / đặt câu hỏi.

Theo cách giải thích về công nghệ, điều này rất giống với tương tác console / shell / cmd vs GUI. (Đó là câu trả lời của Mark Harrison trên câu trả lời hàng đầu số 2). Trong bảng điều khiển, bạn phụ thuộc vào những gì đang được hỏi / hiển thị cho bạn và bạn không thể chuyển sang các menu và tính năng khác mà không trả lời câu hỏi trước; theo một dòng tuần tự nghiêm ngặt. (lập trình này giống như một vòng lặp phương thức / hàm). Tuy nhiên, với GUI, các menu và tính năng được trình bày và người dùng có thể chọn bất cứ thứ gì nó cần do đó có nhiều quyền kiểm soát hơn và ít bị hạn chế hơn. (lập trình, các menu có cuộc gọi lại khi được chọn và một hành động diễn ra).


6

Đảo ngược điều khiển là về việc chuyển điều khiển từ thư viện sang máy khách. Sẽ có ý nghĩa hơn khi chúng ta nói về một máy khách đưa (truyền) một giá trị hàm (biểu thức lambda) vào hàm bậc cao hơn (hàm thư viện) để điều khiển (thay đổi) hành vi của hàm thư viện. Một khách hàng hoặc khung công tác đưa các phụ thuộc thư viện (mang hành vi) vào các thư viện cũng có thể được coi là IoC


5

Vì đã có nhiều câu trả lời cho câu hỏi nhưng không có câu trả lời nào cho thấy sự cố của thuật ngữ Điều khiển đảo ngược, tôi thấy một cơ hội để đưa ra một câu trả lời ngắn gọn và hữu ích hơn.

Đảo ngược điều khiển là một mô hình thực hiện Nguyên tắc đảo ngược phụ thuộc (DIP). DIP nêu các điều sau: 1. Các mô-đun cấp cao không nên phụ thuộc vào các mô-đun cấp thấp. Cả hai nên phụ thuộc vào trừu tượng (ví dụ: giao diện). 2. Trừu tượng không nên phụ thuộc vào chi tiết. Chi tiết (triển khai cụ thể) nên phụ thuộc vào trừu tượng.

Có ba loại Đảo ngược điều khiển:

Nhà cung cấp đảo ngược giao diện không nên xác định một giao diện. Thay vào đó, người tiêu dùng nên xác định giao diện và nhà cung cấp phải thực hiện nó. Giao diện đảo ngược cho phép loại bỏ sự cần thiết phải sửa đổi người tiêu dùng mỗi khi nhà cung cấp mới thêm vào.

Luồng đảo ngược Thay đổi kiểm soát của dòng chảy. Ví dụ: bạn có một ứng dụng bảng điều khiển nơi bạn yêu cầu nhập nhiều tham số và sau mỗi tham số đã nhập, bạn buộc phải nhấn Enter. Bạn có thể áp dụng Flow Inversion tại đây và triển khai ứng dụng máy tính để bàn trong đó người dùng có thể chọn trình tự nhập thông số, người dùng có thể chỉnh sửa tham số và ở bước cuối cùng, người dùng chỉ cần nhấn Enter một lần.

Đảo ngược sáng tạo Nó có thể được thực hiện bằng các mẫu sau: Mẫu nhà máy, Bộ định vị dịch vụ và Tiêm phụ thuộc. Creation Inversion giúp loại bỏ sự phụ thuộc giữa các loại di chuyển quá trình tạo đối tượng phụ thuộc bên ngoài loại sử dụng các đối tượng phụ thuộc này. Tại sao phụ thuộc là xấu? Dưới đây là một vài ví dụ: tạo trực tiếp một đối tượng mới trong mã của bạn làm cho việc kiểm tra khó khăn hơn; không thể thay đổi các tham chiếu trong các cụm mà không cần biên dịch lại (vi phạm nguyên tắc OCP); bạn không thể dễ dàng thay thế UI-UI bằng UI-UI.


3
  1. Vậy số 1 ở trên . Đảo ngược kiểm soát là gì?

  2. Bảo trì là điều số một nó giải quyết cho tôi. Nó đảm bảo tôi đang sử dụng các giao diện để hai lớp không thân mật với nhau.

Khi sử dụng một container như Castle Windsor, nó giải quyết vấn đề bảo trì tốt hơn nữa. Có thể trao đổi một thành phần đi đến cơ sở dữ liệu để sử dụng tính bền vững dựa trên tệp mà không thay đổi dòng mã là tuyệt vời (thay đổi cấu hình, bạn đã hoàn tất).

Và một khi bạn nhận được vào thuốc generic, nó thậm chí còn tốt hơn. Hãy tưởng tượng có một nhà xuất bản tin nhắn nhận hồ sơ và xuất bản tin nhắn. Nó không quan tâm những gì nó xuất bản, nhưng nó cần một người lập bản đồ để lấy thứ gì đó từ bản ghi thành tin nhắn.

public class MessagePublisher<RECORD,MESSAGE>
{
    public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
    {
      //setup
    }
}

Tôi đã viết nó một lần, nhưng bây giờ tôi có thể tiêm nhiều loại vào bộ mã này nếu tôi xuất bản các loại thông báo khác nhau. Tôi cũng có thể viết các trình ánh xạ ghi lại cùng loại và ánh xạ chúng tới các thông điệp khác nhau. Sử dụng DI với Generics đã cho tôi khả năng viết rất ít mã để hoàn thành nhiều nhiệm vụ.

Ồ vâng, có những lo ngại về khả năng kiểm tra, nhưng chúng chỉ là thứ yếu đối với lợi ích của IoC / DI.

Tôi chắc chắn yêu thích IoC / DI.

3. Nó trở nên phù hợp hơn vào phút mà bạn có một dự án cỡ trung bình có phần phức tạp hơn. Tôi muốn nói rằng nó trở nên thích hợp ngay khi bạn bắt đầu cảm thấy đau.



3

Tạo một đối tượng trong lớp được gọi là khớp nối chặt chẽ, Spring loại bỏ sự phụ thuộc này bằng cách tuân theo một mẫu thiết kế (DI / IOC). Trong đó đối tượng của lớp được truyền vào hàm tạo thay vì tạo trong lớp. Hơn nữa, chúng tôi cung cấp biến tham chiếu siêu lớp trong hàm tạo để xác định cấu trúc tổng quát hơ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.