Inversion of Control (IoC) có thể khá khó hiểu khi lần đầu tiên gặp phải.
- Nó là gì?
- Vấn đề nào nó giải quyết?
- Khi nào thì thích hợp để sử dụng và khi nào thì không?
Inversion of Control (IoC) có thể khá khó hiểu khi lần đầu tiên gặp phải.
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 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 TextEditor
và SpellChecker
. 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à TextEditor
lớp trực tiếp phụ thuộc vào SpellChecker
lớ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ó SpellChecker
lớp phụ thuộc trong TextEditor
chữ 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 TextEditor
lớp có quyền kiểm soát SpellChecker
việc sử dụng triển khai nào vì chúng ta sẽ thêm phụ thuộc vào TextEditor
chữ ký.
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.
Đả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:
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ụ
what-to-do
vàwhen-to-do
Đả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.
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).
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:
Nhược điểm:
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ó.
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.
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.
Đả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ã.
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.
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.
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.
Đả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.
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.
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.
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 .
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ụ
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 .
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 .
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:-
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?
Đả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.
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.
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:
Sử dụng tiêm phụ thuộc
Đây là cách một mã sử dụng DI sẽ hoạt động thô:
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 new
từ 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.
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. "
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
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):
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 :)
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.
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.
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ư:
...
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:
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ó và 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à DogService và CatService , 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àng và tô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ó và 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ệ.
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).
Đả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
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.
Vậy số 1 ở trên . Đảo ngược kiểm soát là gì?
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.
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.