Đảo ngược kiểm soát là gì và khi nào tôi nên sử dụng nó?


64

Tôi đang thiết kế một hệ thống mới và tôi muốn biết điều khiển đảo ngược (IOC) là gì và quan trọng hơn là khi nào nên sử dụng nó.

Nó có phải được thực hiện với các giao diện hoặc có thể được thực hiện với các lớp không?


Câu trả lời:


62

IoC (xem Inversion of Control trên Wikipedia) có thể áp dụng trong trường hợp một thành phần không thể thực hiện một nhiệm vụ hoàn toàn vì nó không có một số thông tin hoặc chức năng cần thiết.

Ví dụ đơn giản nhất về mẫu IoC sẽ là các hàm gọi lại trong C. Ví dụ: bạn có thể khai báo hàm:

void Iterator(void *list, Func* f)

Lặp đi lặp lại listviệc áp dụng fchức năng cho từng mục của nó. Các Iteratorchức năng không biết làm thế nào mỗi mục sẽ được xử lý, bạn chỉ cần cung cấp một chức năng như một cuộc tranh cãi, và nó xử lý chúng.

Như ví dụ trước đây cho thấy, IoC cho phép bạn tách chương trình của bạn thành các thành phần riêng biệt không biết về nhau. Một trong những phiên bản phổ biến nhất của IoCDependecy Injection .

Trong Dependency Injection, mỗi thành phần phải khai báo một danh sách các phụ thuộc cần thiết để thực hiện nhiệm vụ của nó. Trong thời gian chạy, một thành phần đặc biệt (thường) được gọi là IoC Container thực hiện liên kết giữa các thành phần này. Nó cố gắng cung cấp các giá trị cho các phụ thuộc thành phần được công bố.

Đây là một ví dụ trong mã giả:

class Foo 
{ 
   <Require Boo>Constructor(Boo boo){ boo.DoSomething } 
}

Trong ví dụ này, lớp Foocó một hàm tạo yêu cầu đối số kiểu Boođể thực hiện một số hành động.

Bạn có thể tạo một thể hiện của lớp Foobằng mã tương tự như sau:

MyContainer.Create(typeof Foo)

MyContainer- là một IoC Container , đảm nhiệm việc lấy ví dụ Boovà chuyển nó đến hàm Footạo.

Tóm lại, IoC cho phép bạn tách chương trình của bạn thành các phần riêng biệt. Điều này là tốt bởi vì:

  • Các thành phần có thể dễ dàng được kiểm tra độc lập.
  • Sự phức tạp của chương trình có thể được giảm bớt.
  • Bạn có thể chuyển các thành phần để thực hiện khác.

Tuy nhiên, trong một số trường hợp, IoC có thể khiến mã khó hiểu hơn.

Nếu bạn muốn xem ví dụ hay về việc sử dụng IoC trong thế giới thực , hãy xem Khối ứng dụng UI hỗn hợp Mircosoft và CompositeWPF

Tôi hy vọng lời giải thích của tôi giúp bạn.

Trân trọng,
aku


1
Năm năm sau, nhưng vẫn .... Đó là một mô tả xuất sắc. Cảm ơn.
Nick Hodges

4
Không được đề cập nhiều ở bất cứ đâu về IoC là thực tế rằng mã trở nên khó đọc hơn. Khả năng đọc là ưu tiên số một nếu bạn muốn viết phần mềm tuyệt vời. Nó thậm chí còn đánh bại Testability. Bạn có thể tách mã tốt ngoài tính hữu dụng của nó.
Arne Evertsson

Vì vậy, một mã sử dụng giải pháp dựa trên Giao diện cho tất cả các phụ thuộc của nó cũng dựa trên thiết kế IoC?
nikel

18

Vì tôi đã tự mình tìm hiểu điều này gần đây và giữ tất cả các dấu trang, nên sau đây tôi thấy vô giá khi tìm hiểu về IOC / DI.

Martin Fowlers Bài viết gốc về IOC / DI

Một số khái niệm cần biết trước

Một bộ sưu tập tuyệt vời các hướng dẫn IOC / DI

Sách trên IOC / DI từ Manning Press

Nguồn và Giải thích về cách tạo IOC của riêng bạn - Nguyên nhân đọc mã nguồn luôn là cách tốt nhất để hiểu một khái niệm.


4

Xin chào JMS, về cơ bản IoC / DI sẽ cho phép bạn xác định việc triển khai nào bạn đang sử dụng một lần và giữ một bản sao tĩnh của vùng chứa của bạn để tham chiếu mỗi khi bạn muốn tham chiếu nó.

Wikipedia có thể sẽ giúp bạn, nhưng tôi muốn tham khảo phần thứ hai của bạn - vâng, việc tiêm phụ thuộc có thể được thực hiện cho các lớp (nghĩa là mỗi khi loại lớp này cần được truyền vào một phương thức, hãy sử dụng lớp này), nhưng tốt hơn là sử dụng các giao diện, bởi vì theo cách đó bạn có thể thay đổi phiên bản của nhà cung cấp, kho lưu trữ, v.v. bạn đang sử dụng chỉ bằng cách tham chiếu lại nó trong thiết lập của mình.

IE, giả sử bạn đã có một giao diện để đọc một luồng và bạn đã có một triển khai XMLStreamReader và SQLStreamReader. Sau đó, bạn có thể chuyển tham chiếu đến giao diện cho các phương thức của mình và sau đó trong bộ chứa IoC của bạn cho nó biết cái nào sẽ sử dụng.

Vì vậy, bạn có thể có Danh sách công khai ReadP People (trình đọc IStreamReader) và trong thiết lập của bạn cho bộ chứa IoC của bạn, hãy nói với nó, mỗi khi bạn mong đợi IStreamReader sử dụng SQLStreamReader.

Sau đó, nếu bạn đổi ý sau này, bạn chỉ cần thay đổi nó ở một nơi (thiết lập vùng chứa của bạn) và sẽ không có vấn đề bao nhiêu phương thức yêu cầu IStreamReader, nó sẽ luôn nhận được mặc định mà bạn đã nói với container của mình phục vụ lên


3

Giả sử bạn có trình xác nhận để kiểm tra xem một doanh nghiệp có hợp lệ trong hệ thống của bạn hay không. "BusinessValidator" của bạn có thể có trường loại Địa chỉ xác thực, xác thực phần địa chỉ của doanh nghiệp. Nếu bạn muốn kiểm tra BusinessValidator mà không thực thi mã bên ngoài (tức là mã addressValidator) thì nếu bạn đã sử dụng một số loại IoC / DI trong khung của mình, bạn có thể dễ dàng "tiêm" một mock addressValidator vào đó và không phải lo lắng về việc thử nghiệm mã ngoài phạm vi của lớp đang thử nghiệm.

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.