Inversion of Control là một nguyên tắc thiết kế chung của kiến trúc phần mềm hỗ trợ trong việc tạo các khung phần mềm mô đun có thể tái sử dụng, dễ bảo trì.
Đó là một nguyên tắc thiết kế trong đó Flow of Control được "nhận" từ thư viện viết chung hoặc mã có thể tái sử dụng.
Để hiểu rõ hơn về nó, hãy xem cách chúng ta sử dụng mã trong những ngày đầu mã hóa. Trong các ngôn ngữ thủ tục / truyền thống, logic nghiệp vụ thường kiểm soát luồng của ứng dụng và "Gọi" mã / hàm chung hoặc có thể sử dụng lại. Ví dụ, trong một ứng dụng Console đơn giản, luồng điều khiển của tôi được điều khiển bởi các hướng dẫn của chương trình, có thể bao gồm các cuộc gọi đến một số chức năng có thể sử dụng lại chung.
print ("Please enter your name:");
scan (&name);
print ("Please enter your DOB:");
scan (&dob);
//More print and scan statements
<Do Something Interesting>
//Call a Library function to find the age (common code)
print Age
Ngược lại, với IoC, Framework là mã có thể tái sử dụng "Gọi" logic kinh doanh.
Ví dụ, trong một hệ thống dựa trên cửa sổ, một khung sẽ có sẵn để tạo các thành phần UI như nút, menu, cửa sổ và hộp thoại. Khi tôi viết logic nghiệp vụ cho ứng dụng của mình, đó sẽ là các sự kiện của khung sẽ gọi mã logic nghiệp vụ của tôi (khi một sự kiện được kích hoạt) và KHÔNG ngược lại.
Mặc dù, mã của khung không nhận thức được logic kinh doanh của tôi, nhưng nó vẫn sẽ biết cách gọi mã của tôi. Điều này đạt được bằng cách sử dụng các sự kiện / đại biểu, cuộc gọi lại, vv Ở đây, Kiểm soát luồng là "Đảo ngược".
Vì vậy, thay vì phụ thuộc vào luồng điều khiển trên các đối tượng bị ràng buộc tĩnh, luồng này phụ thuộc vào biểu đồ đối tượng tổng thể và các mối quan hệ giữa các đối tượng khác nhau.
Dependency Injection là một mẫu thiết kế thực hiện nguyên tắc IoC để giải quyết các phụ thuộc của các đối tượng.
Nói một cách đơn giản hơn, khi bạn đang cố gắng viết mã, bạn sẽ tạo và sử dụng các lớp khác nhau. Một lớp (Lớp A) có thể sử dụng các lớp khác (Lớp B và / hoặc D). Vì vậy, lớp B và D là các phụ thuộc của lớp A.
Một tương tự đơn giản sẽ là một chiếc xe đẳng cấp. Một chiếc xe có thể phụ thuộc vào các lớp khác như Động cơ, Lốp và nhiều hơn nữa.
Dependency Injection gợi ý rằng thay vì các lớp Phụ thuộc (Class Car ở đây) tạo ra các phụ thuộc của nó (Class Engine và Class Tyre), lớp nên được tiêm với thể hiện cụ thể của phụ thuộc.
Hãy hiểu với một ví dụ thực tế hơn. Hãy xem xét rằng bạn đang viết TextEditor của riêng bạn. Trong số những thứ khác, bạn có thể có một trình kiểm tra chính tả cung cấp cho người dùng một phương tiện để kiểm tra lỗi chính tả trong văn bản của mình. Một triển khai đơn giản của một mã như vậy có thể là:
Class TextEditor
{
//Lot of rocket science to create the Editor goes here
EnglishSpellChecker objSpellCheck;
String text;
public void TextEditor()
{
objSpellCheck = new EnglishSpellChecker();
}
public ArrayList <typos> CheckSpellings()
{
//return Typos;
}
}
Ngay từ cái nhìn đầu tiên, tất cả đều có vẻ hồng hào. Người dùng sẽ viết một số văn bản. Nhà phát triển sẽ nắm bắt văn bản và gọi chức năng CheckSpellings và sẽ tìm thấy một danh sách Typose mà anh ta sẽ hiển thị cho Người dùng.
Mọi thứ dường như hoạt động tuyệt vời cho đến một ngày đẹp trời khi một người dùng bắt đầu viết tiếng Pháp trong Trình chỉnh sửa.
Để cung cấp hỗ trợ cho nhiều ngôn ngữ hơn, chúng tôi cần có thêm SpellCheckers. Có lẽ là tiếng Pháp, tiếng Đức, tiếng Tây Ban Nha, v.v.
Ở đây, chúng tôi đã tạo ra một mã được ghép chặt chẽ với SpellChecker "tiếng Anh" được kết hợp chặt chẽ với lớp TextEditor của chúng tôi, điều đó có nghĩa là lớp TextEditor của chúng tôi phụ thuộc vào EnglishSpellChecker hoặc nói cách khác EnglishSpellCheker là phụ thuộc cho TextEditor. Chúng ta cần loại bỏ sự phụ thuộc này. Hơn nữa, Trình chỉnh sửa văn bản của chúng tôi cần một cách để giữ tham chiếu cụ thể của bất kỳ Trình kiểm tra chính tả nào dựa trên quyết định của nhà phát triển trong thời gian chạy.
Vì vậy, như chúng ta đã thấy trong phần giới thiệu của DI, nó gợi ý rằng lớp nên được thêm vào các phụ thuộc của nó. Vì vậy, trách nhiệm của mã gọi là tiêm tất cả các phụ thuộc vào lớp / mã được gọi. Vì vậy, chúng tôi có thể cơ cấu lại mã của chúng tôi như
interface ISpellChecker
{
Arraylist<typos> CheckSpelling(string Text);
}
Class EnglishSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
//All Magic goes here.
}
}
Class FrenchSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
//All Magic goes here.
}
}
Trong ví dụ của chúng ta, lớp TextEditor sẽ nhận được thể hiện cụ thể của loại ISpellChecker.
Bây giờ, sự phụ thuộc có thể được đưa vào Con Contor, một thuộc tính công cộng hoặc một phương thức.
Hãy thử thay đổi lớp của chúng tôi bằng cách sử dụng Trình xây dựng DI. Lớp TextEditor đã thay đổi sẽ trông giống như:
Class TextEditor
{
ISpellChecker objSpellChecker;
string Text;
public void TextEditor(ISpellChecker objSC)
{
objSpellChecker = objSC;
}
public ArrayList <typos> CheckSpellings()
{
return objSpellChecker.CheckSpelling();
}
}
Vì vậy, mã cuộc gọi, trong khi tạo trình soạn thảo văn bản có thể đưa Loại SpellChecker thích hợp vào thể hiện của TextEditor.
Bạn có thể đọc bài viết đầy đủ ở đây