Đảo ngược kiểm soát so với tiêm phụ thuộc


525

Theo bài báo của Martin Fowler , đảo ngược điều khiển là nguyên tắc mà luồng điều khiển của chương trình bị đảo ngược: thay vì lập trình viên điều khiển luồng chương trình, các nguồn bên ngoài (khung, dịch vụ, các thành phần khác) kiểm soát nó Giống như chúng ta cắm thứ gì đó vào thứ khác. Ông đã đề cập một ví dụ về EJB 2.0:

Ví dụ: giao diện Session Bean định nghĩa ejbRemove, ejbPassivate (được lưu trữ vào bộ lưu trữ thứ cấp) và ejbActivate (được khôi phục từ trạng thái thụ động). Bạn không thể kiểm soát khi các phương thức này được gọi, chỉ là những gì chúng làm. Container gọi cho chúng tôi, chúng tôi không gọi nó.

Điều này dẫn đến sự khác biệt giữa khung và thư viện:

Inversion of Control là một phần quan trọng của những gì làm cho một khung khác với thư viện. Một thư viện về cơ bản là một tập hợp các hàm mà bạn có thể gọi, ngày nay thường được tổ chức thành các lớp. Mỗi cuộc gọi thực hiện một số công việc và trả lại quyền điều khiển cho máy khách.

Tôi nghĩ, quan điểm cho rằng DI là IOC, có nghĩa là sự phụ thuộc của một đối tượng bị đảo ngược: thay vì nó kiểm soát sự phụ thuộc của chính nó, vòng đời ... một cái gì đó khác làm cho bạn. Nhưng, như bạn đã nói với tôi về DI bằng tay, DI không nhất thiết phải là IOC. Chúng ta vẫn có thể có DI và không có IOC.

Tuy nhiên, trong bài báo này (từ pococapsule, một IOC Framework khác cho C / C ++), nó gợi ý rằng vì IOC và DI, các thùng chứa IOC và khung DI vượt trội hơn nhiều so với J2EE, vì J2EE trộn mã khung vào các thành phần , do đó không làm cho nó trở thành đối tượng Java / C ++ cũ (POJO / POCO).

Đảo ngược các Container kiểm soát khác với mẫu Tiêm phụ thuộc (liên kết Lưu trữ)

Đọc thêm để hiểu vấn đề gì với Khung phát triển dựa trên thành phần cũ, dẫn đến bài viết thứ hai ở trên: Tại sao và điều gì xảy ra trong Đảo ngược điều khiển (Liên kết lưu trữ)

Câu hỏi của tôi : IOC và DI chính xác là gì? Tôi bị bối rối. Dựa trên pococapsule, IOC là một cái gì đó quan trọng hơn là chỉ đảo ngược sự kiểm soát giữa các đối tượng hoặc lập trình viên và khung.


2
Đây là một bài viết hay về chủ đề này, IoC vs DI (Dependency Injection) vs SL (Service Locator): tinyurl.com/kk4be58 - Trích xuất từ ​​url: IoC vs DI (Dependency Injection)? IoC là khái niệm chung, nơi kiểm soát dòng chảy được Inverted từ mã khách hàng để khuôn khổ, mà “làm điều gì đó cho khách hàng”. SL (Service Locator) và DI (Dependency Injection) là hai mẫu thiết kế xuất phát từ IoC.
Swab.Jat

Để thêm hai xu của tôi, nếu một người quan tâm đến việc tiêm phụ thuộc có thể hữu ích như thế nào trong chủ đề quán cà phê, tôi đã viết một bài viết về điều đó tại đây: digigene.com/design-potypes/dependency-injection-coffeeshop
Ali Nem

3
bài viết phù hợp cho người mới bắt đầu asimplify.com/dependency-injection-inversion-control
Khawaja Asim

Phụ thuộc đảo ngược: Phụ thuộc vào trừu tượng, không phụ thuộc vào cụ thể. Đảo ngược điều khiển: Chính so với Trừu tượng và cách Chính là chất keo của các hệ thống. Đây là một số bài viết hay nói về điều này: coderstower.com/2019/03/26/ trên coderstower.com/2019/04/02/ trên coderstower.com/2019/04/09/ Lỗi
Daniel Andres Pelaez Lopez

đọc về điều này sâu sắc, nó sẽ xóa tất cả martinfowler.com/articles/ từ
Dushman

Câu trả lời:


644

IoC là một thuật ngữ chung có nghĩa thay vì yêu cầu ứng dụng gọi các phương thức trong một khung, khung gọi các triển khai được cung cấp bởi ứng dụng.

DI là một dạng của IoC, nơi các triển khai được truyền vào một đối tượng thông qua các hàm tạo / setters / tra cứu dịch vụ, mà đối tượng sẽ 'phụ thuộc' vào để hành xử chính xác.

IoC mà không sử dụng DI , ví dụ sẽ là mẫu Mẫu vì việc triển khai chỉ có thể được thay đổi thông qua phân lớp.

Các khung DI được thiết kế để sử dụng DI và có thể định nghĩa các giao diện (hoặc Chú thích trong Java) để giúp dễ dàng vượt qua trong các triển khai.

IoC Container là các khung DI có thể hoạt động bên ngoài ngôn ngữ lập trình. Trong một số bạn có thể định cấu hình triển khai nào sẽ sử dụng trong các tệp siêu dữ liệu (ví dụ: XML) ít xâm lấn hơn. Với một số bạn có thể làm IoC mà thông thường là không thể như tiêm một triển khai tại các điểm cắt .

Xem thêm bài viết này của Martin Fowler .


2
Cảm ơn câu trả lời. Nhưng bài báo khác cho thấy rằng với IOC, các thùng chứa IOC vượt trội hơn nhiều so với EJB, trong khi Martin Fowler cho rằng EJB là một ví dụ điển hình của IOC.
Amumu

5
Quản lý EJB thực sự là một ví dụ điển hình của IoC. Bạn có thể thấy điều đó từ thực tế là vòng đời của EJB được quản lý bởi container chứ không phải bởi lập trình viên. Lập trình viên không tạo hoặc hủy một cá thể EJB vì điều khiển được ủy quyền cho máy chủ . Đó là khái niệm về IoC: mã bên ngoài kiểm soát khi mã của bạn được gọi, thường là nghịch đảo của những gì nó được thực hiện hầu hết thời gian.
brandizzi

2
IoC là một thuật ngữ chung có nghĩa thay vì yêu cầu ứng dụng gọi các phương thức trong một khung, khung gọi các triển khai được cung cấp bởi ứng dụng. Bạn có thể giải thích thêm về điều này?
Imad Alazani

21
Nguyên tắc của Aka Hollywood , 'đừng gọi cho chúng tôi, chúng tôi sẽ gọi cho bạn'. Để lại lời mời lên khung chứ không phải ứng dụng.
Hội trường Garrett

@ImadAlazani, bạn nên đọc qua bài viết mà Garrett đính kèm, đây là một cuộc thảo luận chi tiết về việc đảo ngược điều khiển từ mã ứng dụng sang khung.
MạnhT

210

Nói tóm lại, IoC là một thuật ngữ rộng hơn bao gồm, nhưng không giới hạn ở, DI

Thuật ngữ Inversion of Control (IoC) ban đầu có nghĩa là bất kỳ loại phong cách lập trình nào trong đó một khung tổng thể hoặc thời gian chạy kiểm soát luồng chương trình

Trước khi DI có tên, mọi người bắt đầu đề cập đến các khung quản lý Dependencies là Inversion of Control Container, và chẳng bao lâu, ý nghĩa của IoC dần dần chuyển sang ý nghĩa đặc biệt đó: Đảo ngược kiểm soát phụ thuộc.

Inversion of Control (IoC) có nghĩa là các đối tượng không tạo ra các đối tượng khác mà chúng dựa vào để thực hiện công việc của mình. Thay vào đó, họ lấy các đối tượng mà họ cần từ nguồn bên ngoài (ví dụ: tệp cấu hình xml).

Dependency Injection (DI) có nghĩa là việc này được thực hiện mà không có sự can thiệp của đối tượng, thường là bởi một thành phần khung truyền các tham số của hàm tạo và đặt thuộc tính.


1
Có vẻ như IoC chỉ là một thuật ngữ khác cho nguyên tắc Depency Inversion, phải không?
Todd Vance

@ToddVance - Vâng, tôi nghĩ IoC và DIP là cùng một thứ. Dip và DI không giống nhau. IoC có thể được thực hiện mà không có DI, nhưng DI không thể được thực hiện mà không có IoC.
Eljay

2
@ToddVance - Không, DIP và IoC không phải là từ đồng nghĩa và không liên quan.
TSmith

3
Ha, đó là lý do tại sao tôi ở đây trong chủ đề này ... "Đảo ngược kiểm soát và tiêm phụ thuộc"
Todd Vance

50

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

IoC ( I nversion o f C ontrol): - Đó là một thuật ngữ chung và được triển khai theo nhiều cách (sự kiện, đại biểu, v.v.).

DI ( D ependency I njection): - DI là một kiểu con của IoC và được triển khai bằng cách xây dựng, tiêm setter hoặc tiêm Interface .

Nhưng, Spring chỉ hỗ trợ hai loại sau:

  • Setter tiêm
    • DI dựa trên Setter được nhận ra bằng cách gọi các phương thức setter trên các bean của người dùng sau khi gọi một hàm tạo không có đối số hoặc phương thức nhà máy tĩnh không đối số để khởi tạo bean của chúng.
  • Xây dựng tiêm
    • DI dựa trên trình xây dựng được thực hiện bằng cách gọi một hàm tạo với một số đối số, mỗi đối số đại diện cho một cộng tác viên. Sử dụng điều này chúng ta có thể xác nhận rằng các hạt được tiêm không rỗng và thất bại nhanh (thất bại trong thời gian biên dịch và không phải trong thời gian chạy), vì vậy Trong khi bắt đầu ứng dụng, chúng tôi nhận được NullPointerException: bean does not exist. Con constructor tiêm là thực hành tốt nhất để tiêm phụ thuộc.

1
không đúng khi nói rằng Spring không hỗ trợ tiêm tài sản. Nó làm. Và đó là một thực tế xấu, tôi đồng ý.
kekko12

Theo ý kiến ​​của tôi, Spring @Autowired là một cách tiêm tài sản theo quan điểm của tôi
Sajith

49

DI là tập con của IoC

  • IoC có nghĩa là các đối tượng không tạo ra các đối tượng khác mà họ dựa vào để thực hiện công việc của mình. Thay vào đó, họ nhận được các đối tượng mà họ cần từ một dịch vụ bên ngoài (ví dụ: tệp xml hoặc dịch vụ ứng dụng đơn lẻ). Tôi sử dụng 2 triển khai IoC là DI và ServiceLocator.
  • DI có nghĩa là nguyên tắc IoC để có được đối tượng phụ thuộc được thực hiện mà không sử dụng các đối tượng cụ thể nhưng trừu tượng hóa (giao diện). Điều này làm cho tất cả các chuỗi thành phần có thể kiểm tra được, vì thành phần cấp cao hơn không phụ thuộc vào thành phần cấp thấp hơn, chỉ từ giao diện. Mocks thực hiện các giao diện này.

Dưới đây là một số kỹ thuật khác để đạt được IoC .


Tôi sẽ không nói IoC có nghĩa là không tạo ra các đối tượng. Khi bạn gọi không phải là phương thức lớp trực tiếp, mà là phương thức giao diện - đây là sự đảo ngược của điều khiển (như trong trường hợp này, người gọi không phụ thuộc vào mã gọi) và nó hoàn toàn không liên quan đến việc tạo đối tượng. Một ví dụ nữa về IoC là các sự kiện và đại biểu
Eugene Gorbovoy

19

Vì tất cả các câu trả lời nhấn mạnh vào lý thuyết, tôi muốn chứng minh bằng một ví dụ về cách tiếp cận đầu tiên:

Giả sử chúng tôi đang xây dựng một ứng dụng có tính năng gửi tin nhắn xác nhận SMS sau khi đơn hàng đã được chuyển đi. Chúng tôi sẽ có hai lớp, một lớp chịu trách nhiệm gửi SMS (SMSService) và một lớp khác chịu trách nhiệm nắm bắt đầu vào của người dùng (UIHandler), mã của chúng tôi sẽ như sau:

public class SMSService
{
    public void SendSMS(string mobileNumber, string body)
    {
        SendSMSUsingGateway(mobileNumber, body);
    }

    private void SendSMSUsingGateway(string mobileNumber, string body)
    {
        /*implementation for sending SMS using gateway*/
    }
}

public class UIHandler
{
    public void SendConfirmationMsg(string mobileNumber)
    {
        SMSService _SMSService = new SMSService();
        _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
    }
}

Thực hiện ở trên không sai nhưng có một số vấn đề:
-) Giả sử Trên môi trường phát triển, bạn muốn lưu SMS được gửi vào tệp văn bản thay vì sử dụng cổng SMS, để đạt được điều này; cuối cùng chúng tôi sẽ thay đổi việc triển khai cụ thể (SMSService) bằng một triển khai khác, chúng tôi đang mất tính linh hoạt và buộc phải viết lại mã trong trường hợp này.
-) Chúng tôi sẽ kết thúc trách nhiệm pha trộn của các lớp, (UIHandler) của chúng tôi sẽ không bao giờ biết về việc triển khai cụ thể (SMSService), điều này nên được thực hiện bên ngoài các lớp bằng cách sử dụng Giao diện xen kẽ. Khi điều này được thực hiện, nó sẽ cho chúng ta khả năng thay đổi hành vi của hệ thống bằng cách hoán đổi (SMSService) được sử dụng với một dịch vụ giả khác có cùng giao diện, dịch vụ này sẽ lưu SMS vào tệp văn bản thay vì gửi đến mobileNumber.

Để khắc phục các sự cố trên, chúng tôi sử dụng Giao diện sẽ được triển khai bởi (SMSService) và mới (MockSMSService), về cơ bản Giao diện mới (ISMSService) sẽ hiển thị các hành vi tương tự của cả hai dịch vụ như mã dưới đây:

public interface ISMSService
{
    void SendSMS(string phoneNumber, string body);
}

Sau đó, chúng tôi sẽ thay đổi triển khai (SMSService) để triển khai giao diện (ISMSService):

public class SMSService : ISMSService
{
    public void SendSMS(string mobileNumber, string body)
    {
        SendSMSUsingGateway(mobileNumber, body);
    }

    private void SendSMSUsingGateway(string mobileNumber, string body)
    {
        /*implementation for sending SMS using gateway*/
        Console.WriteLine("Sending SMS using gateway to mobile: 
        {0}. SMS body: {1}", mobileNumber, body);
    }
}

Bây giờ chúng tôi sẽ có thể tạo dịch vụ giả lập mới (MockSMSService) với cách triển khai hoàn toàn khác bằng cùng một giao diện:

public class MockSMSService :ISMSService
{
    public void SendSMS(string phoneNumber, string body)
    {
        SaveSMSToFile(phoneNumber,body);
    }

    private void SaveSMSToFile(string mobileNumber, string body)
    {
        /*implementation for saving SMS to a file*/
        Console.WriteLine("Mocking SMS using file to mobile: 
        {0}. SMS body: {1}", mobileNumber, body);
    }
}

Tại thời điểm này, chúng tôi có thể thay đổi mã trong (UIHandler) để sử dụng triển khai cụ thể dịch vụ (MockSMSService) như sau:

public class UIHandler
{
    public void SendConfirmationMsg(string mobileNumber)
    {
        ISMSService _SMSService = new MockSMSService();
        _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
    }
}

Chúng tôi đã đạt được rất nhiều tính linh hoạt và thực hiện phân tách mối quan tâm trong mã của mình, nhưng chúng tôi vẫn cần thực hiện thay đổi trên cơ sở mã để chuyển đổi giữa hai Dịch vụ SMS. Vì vậy, chúng ta cần phải thực hiện Dependency Injection .

Để đạt được điều này, chúng ta cần thực hiện thay đổi đối với hàm tạo của lớp (UIHandler) để vượt qua sự phụ thuộc thông qua nó, bằng cách này, mã sử dụng (UIHandler) có thể xác định việc triển khai cụ thể (ISMSService) nào sẽ sử dụng:

public class UIHandler
{
    private readonly ISMSService _SMSService;

    public UIHandler(ISMSService SMSService)
    {
        _SMSService = SMSService;
    }

    public void SendConfirmationMsg(string mobileNumber)
    {
        _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
    }
}

Bây giờ biểu mẫu UI sẽ nói chuyện với lớp (UIHandler) có trách nhiệm thông qua việc triển khai giao diện (ISMSService) nào để sử dụng. Điều này có nghĩa là chúng tôi đã đảo ngược điều khiển, (UIHandler) không còn chịu trách nhiệm quyết định sử dụng triển khai nào, mã gọi thực hiện. Chúng tôi đã thực hiện nguyên tắc Đảo ngược điều khiển mà DI là một loại của nó.

Mã hình thức UI sẽ như sau:

class Program
{
    static void Main(string[] args)
    {
        ISMSService _SMSService = new MockSMSService(); // dependency

        UIHandler _UIHandler = new UIHandler(_SMSService);
        _UIHandler.SendConfirmationMsg("96279544480");

        Console.ReadLine();
    }
}

Giải thích tuyệt vời
ZiviMagic

19

IOC (Inversion Of Control) : Cung cấp điều khiển cho vùng chứa để lấy một thể hiện của đối tượng được gọi là Inversion of Control, có nghĩa là thay vì bạn đang tạo một đối tượng bằng toán tử mới, hãy để container làm điều đó cho bạn.

DI (Dependency Injection) : Cách tiêm thuộc tính vào một đối tượng được gọi là Dependency Injection .

Chúng tôi có ba loại tiêm phụ thuộc :

  1. Xây dựng tiêm
  2. Setter / Getter tiêm
  3. Giao diện tiêm

Spring chỉ hỗ trợ Con Contortor tiêmSetter / Getter Injection .


5

Nhưng tài liệu mùa xuân nói rằng họ giống nhau.

http://docs.spring.io/spring/docs/civerse/spring-framework-reference/htmlsingle/#beans-int sinhtion

Trong dòng đầu tiên " IoC còn được gọi là tiêm phụ thuộc (DI) ".


1
Tôi đoán những gì họ đã cố gắng giải quyết là DI là một hương vị được sử dụng rất rộng rãi của mẫu thiết kế IoC mà nó có thể dễ dàng được gọi là IoC hay còn gọi là DI - trừ khi tài liệu có bất kỳ tài liệu tham khảo rõ ràng nào đề xuất khác.
ha9u63ar

5
"IoC còn được gọi là tiêm phụ thuộc (DI)" ... cưỡi ngựa!
MikeM

5

IoC - Đảo ngược điều khiển là thuật ngữ chung, độc lập với ngôn ngữ, nó thực sự không tạo ra các đối tượng mà mô tả trong đó đối tượng thời trang đang được tạo ra.

DI - Dependency Injection là thuật ngữ cụ thể, trong đó chúng tôi cung cấp các phụ thuộc của đối tượng trong thời gian chạy bằng cách sử dụng các kỹ thuật tiêm khác nhau viz. Setter tiêm, tiêm xây dựng hoặc tiêm giao diện.


4

Đảo ngược điều khiển là một mô hình thiết kế với mục tiêu cung cấp thêm quyền kiểm soát cho các thành phần được nhắm mục tiêu trong ứng dụng của bạn, những thành phần hoàn thành công việc.
Phép nội xạ phụ thuộc là một mẫu được sử dụng để tạo các thể hiện của các đối tượng mà các đối tượng khác dựa vào mà không biết tại thời điểm biên dịch lớp nào sẽ được sử dụng để cung cấp chức năng đó.

Có một số kỹ thuật cơ bản để thực hiện đảo ngược điều khiển. Đó là:

  • Sử dụng mẫu nhà máy
  • Sử dụng mẫu định vị dịch vụ
  • Sử dụng một mũi tiêm phụ thuộc của bất kỳ loại nào dưới đây:

    1). Một tiêm xây dựng
    2). Một setter tiêm
    3). Một giao diện tiêm

4

DIIOC là hai mẫu thiết kế chủ yếu tập trung vào việc cung cấp khớp nối lỏng lẻo giữa các thành phần , hoặc đơn giản là cách chúng ta tách rời các mối quan hệ phụ thuộc thông thường giữa các đối tượng để các đối tượng không chặt chẽ với nhau.

Với các ví dụ sau, tôi đang cố gắng giải thích cả hai khái niệm này.

Trước đây chúng tôi đang viết mã như thế này

Public MyClass{
 DependentClass dependentObject
 /*
  At somewhere in our code we need to instantiate 
  the object with new operator  inorder to use it or perform some method.
  */ 
  dependentObject= new DependentClass();
  dependentObject.someMethod();
}

Với tiêm phụ thuộc, người tiêm phụ thuộc sẽ đảm nhiệm việc khởi tạo đối tượng

Public MyClass{
 /* Dependency injector will instantiate object*/
 DependentClass dependentObject

 /*
  At somewhere in our code we perform some method. 
  The process of  instantiation will be handled by the dependency injector
 */ 

  dependentObject.someMethod();
}

Quá trình trao quyền kiểm soát cho một số người khác (ví dụ như container) để khởi tạo và tiêm có thể được gọi là Inversion of Control và quá trình trong đó container IOC tiêm phụ thuộc cho chúng ta có thể được gọi là tiêm phụ thuộc.

IOC là nguyên tắc mà luồng điều khiển của chương trình được đảo ngược: thay vì lập trình viên điều khiển luồng của chương trình , chương trình kiểm soát luồng bằng cách giảm chi phí cho lập trình viên. Và quy trình được sử dụng bởi chương trình để tiêm phụ thuộc được gọi là DI

Hai khái niệm này hoạt động cùng nhau cung cấp cho chúng ta cách viết mã linh hoạt, có thể tái sử dụng và đóng gói nhiều hơn, khiến chúng trở thành các khái niệm quan trọng trong việc thiết kế các giải pháp hướng đối tượng.

Cũng đề nghị đọc.

Tiêm phụ thuộc là gì?

Bạn cũng có thể kiểm tra một trong những câu trả lời tương tự của tôi ở đây

Sự khác biệt giữa nghịch đảo kiểm soát và tiêm phụ thuộc


3

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


3

IOC (Inversion Of Control): Trao quyền điều khiển cho vùng chứa để lấy đối tượng được gọi là Inversion of Control. Nó có nghĩa là thay vì bạn đang tạo đối tượng bằng toán tử mới , hãy để container làm điều đó cho bạn.

DI (Dependency Injection): Truyền các tham số (thuộc tính) cần thiết từ XML đến một đối tượng (trong POJO CLASS) được gọi là tiêm Dependency.


2

IOC chỉ ra rằng một lớp bên ngoài quản lý các lớp của một ứng dụng và các lớp bên ngoài có nghĩa là một thùng chứa quản lý sự phụ thuộc giữa các lớp của ứng dụng. Khái niệm cơ bản của IOC là lập trình viên không cần tạo đối tượng của bạn mà mô tả cách tạo chúng.

Các tác vụ chính được thực hiện bởi bộ chứa IoC là: khởi tạo lớp ứng dụng. để cấu hình đối tượng. để lắp ráp các phụ thuộc giữa các đối tượng.

DI là quá trình cung cấp các phụ thuộc của một đối tượng trong thời gian chạy bằng cách sử dụng phép tiêm setter hoặc hàm tạo.


2

IOC (Inversion of Control) về cơ bản là thiết kế khái niệm mẫu để loại bỏ các phụ thuộc và tách chúng ra để làm cho dòng không tuyến tính và để cho container / hoặc một thực thể khác quản lý việc cung cấp các phụ thuộc. Nó thực sự theo hiệu trưởng Hollywood Đừng gọi chúng tôi, chúng tôi sẽ gọi bạn là. Vì vậy, tóm tắt sự khác biệt.

Đảo ngược quyền kiểm soát: - Đây là một thuật ngữ chung để tách rời các phụ thuộc và ủy thác việc cung cấp của họ và điều này có thể được thực hiện theo nhiều cách (sự kiện, đại biểu, v.v.).

Tiêm phụ thuộc: - DI là một kiểu con của IOC và được thực hiện bằng cách tiêm xây dựng, tiêm setter hoặc tiêm phương pháp.

Bài viết sau đây mô tả điều này rất gọn gàng.

https://www.codeproject.com/Articles/592372/Dependency-Injection-DI-vs-Inversion-of-Control-IO


1

Tôi nghĩ rằng ý tưởng có thể được thể hiện rõ ràng mà không cần đi sâu vào các loại cỏ hướng đối tượng, dường như làm vấy bẩn ý tưởng.

// dependency injection
function doSomething(dependency) {
    // do something with your dependency
}

// in contrast to creating your dependencies yourself
function doSomething() {
    dependency = getDependencySomehow()
}

// inversion of control
application = makeApp(authenticate, handleRequest, sendResponse)
application.run(getRequest())

// in contrast to direct control or a "library" style
application = makeApp()
request = application.getRequest()

if (application.authenticate(request.creds)) {
    response = application.handleRequest(request)
    application.sendResponse(response)
}

Nếu bạn nghiêng đầu và nheo mắt, bạn sẽ thấy DI là một triển khai cụ thể của IoC với những mối quan tâm cụ thể. Thay vì đưa các mô hình và hành vi vào một khung ứng dụng hoặc hoạt động theo thứ tự cao hơn, bạn đang đưa các biến vào một hàm hoặc đối tượng.


0

Hãy bắt đầu với D của RẮN và xem DI và IoC từ cuốn sách "Các mẫu thiết kế ASP.NET chuyên nghiệp" của Scott Millett:

Nguyên tắc đảo ngược phụ thuộc (DIP)

Các DIP là tất cả về cô lập lớp học của bạn từ việc triển khai cụ thể và có họ phụ thuộc vào lớp trừu tượng hoặc giao diện. Nó thúc đẩy thần chú mã hóa cho một giao diện chứ không phải là một triển khai, điều này làm tăng tính linh hoạt trong một hệ thống bằng cách đảm bảo bạn không được kết hợp chặt chẽ với một triển khai.

Phụ thuộc tiêm (DI) và đảo ngược kiểm soát (IoC)

Liên kết chặt chẽ với DIP là nguyên tắc DI và nguyên tắc IoC. DI là hành động cung cấp một mức độ thấp hoặc lớp phụ thuộc thông qua một hàm tạo, phương thức hoặc thuộc tính. Được sử dụng cùng với DI, các lớp phụ thuộc này có thể được đảo ngược với các giao diện hoặc các lớp trừu tượng sẽ dẫn đến các hệ thống được ghép lỏng lẻo rất dễ kiểm tra và dễ thay đổi.

Trong IoC , luồng điều khiển của một hệ thống được đảo ngược so với lập trình thủ tục. Một ví dụ về điều này là một container IoC , với mục đích là tiêm các dịch vụ vào mã máy khách mà không cần mã máy khách chỉ định việc triển khai cụ thể. Kiểm soát trong trường hợp này đang bị đảo ngược là hành động của khách hàng có được dịch vụ.

Millett, C (2010). Mẫu thiết kế ASP.NET chuyên nghiệp. Nhà xuất bản Wiley. 7-8.


0

// ICO, DI, 10 năm trước, đây là cách của họ:

public class  AuditDAOImpl implements Audit{

    //dependency
    AuditDAO auditDAO = null;
        //Control of the AuditDAO is with AuditDAOImpl because its creating the object
    public AuditDAOImpl () {
        this.auditDAO = new AuditDAO ();
    }
}

Bây giờ với Spring 3,4 hoặc mới nhất như dưới đây

public class  AuditDAOImpl implements Audit{

    //dependency

     //Now control is shifted to Spring. Container find the object and provide it. 
    @Autowired
    AuditDAO auditDAO = null;

}

Nhìn chung, điều khiển được đảo ngược từ khái niệm cũ về mã được ghép thành các khung như Spring, làm cho đối tượng có sẵn. Vì vậy, đó là IOC theo như tôi biết và tiêm phụ thuộc như bạn biết khi chúng ta tiêm đối tượng phụ thuộc vào đối tượng khác bằng cách sử dụng Trình xây dựng hoặc setters. Tiêm về cơ bản có nghĩa là vượt qua nó như là một đối số. Vào mùa xuân, chúng ta có cấu hình dựa trên XML & chú thích, trong đó chúng ta xác định đối tượng bean và truyền đối tượng phụ thuộc với Con constructor hoặc kiểu setter.


0

Tôi đã tìm thấy ví dụ tốt nhất trên Dzone.com , điều này thực sự hữu ích để hiểu sự khác biệt thực sự giữa IOC và DI

Cấm IoC là khi bạn có người khác tạo đối tượng cho mình. Vì vậy, thay vì viết từ khóa "mới" (Ví dụ: MyCode c = new MyCode ()) trong mã của bạn, đối tượng được tạo bởi người khác. Điều này 'người khác' thường được gọi là một container IoC. Điều đó có nghĩa là chúng tôi bàn giao khả năng ghi lại (điều khiển) cho vùng chứa để lấy đối tượng được gọi là Inversion of Control., Có nghĩa là thay vì bạn đang tạo đối tượng bằng toán tử mới, hãy để container làm điều đó cho bạn.

   DI(Dependency Injection):  Way of injecting properties to an object is 
   called 
  Dependency injection.
   We have three types of Dependency injection
    1)  Constructor Injection
    2)  Setter/Getter Injection
    3)  Interface Injection
   Spring will support only Constructor Injection and Setter/Getter Injection.

Đọc toàn bộ bài viết IOCĐọc toàn bộ bài viết DI


0

1) DI là trẻ em-> obj phụ thuộc vào cha mẹ-obj. Động từ phụ thuộc là quan trọng. 2) IOC là Child-> obj thực hiện dưới một nền tảng. nơi nền tảng có thể là trường học, đại học, lớp khiêu vũ. Ở đây thực hiện là một hoạt động với ý nghĩa khác nhau dưới bất kỳ nhà cung cấp nền tảng nào.

ví dụ thực tế: `

//DI
child.getSchool();
//IOC
child.perform()// is a stub implemented by dance-school
child.flourish()// is a stub implemented by dance-school/school/

`

-AB


0

Đối với câu hỏi này, tôi muốn nói rằng wiki đã cung cấp các giải thích chi tiết và dễ hiểu. Tôi sẽ chỉ trích dẫn quan trọng nhất ở đây.

Triển khai IoC

Trong lập trình hướng đối tượng, có một số kỹ thuật cơ bản để thực hiện đảo ngược điều khiển. Đó là:

  1. Sử dụng mẫu định vị dịch vụ Sử dụng phương pháp tiêm phụ thuộc, ví dụ: Con Conttor tiêm Thông số tiêm Setter tiêm Giao diện tiêm;
  2. Sử dụng một tra cứu theo ngữ cảnh;
  3. Sử dụng mẫu thiết kế phương pháp mẫu;
  4. Sử dụng mẫu thiết kế chiến lược

Đối với tiêm phụ thuộc

tiêm phụ thuộc là một kỹ thuật trong đó một đối tượng (hoặc phương thức tĩnh) cung cấp các phụ thuộc của đối tượng khác. Một phụ thuộc là một đối tượng có thể được sử dụng (một dịch vụ). Một mũi tiêm là việc truyền một phụ thuộc vào một đối tượng phụ thuộc (một khách hàng) sẽ sử dụng nó.


0

Khái niệm IoC ban đầu được nghe trong kỷ nguyên lập trình thủ tục. Do đó, từ bối cảnh lịch sử, IoC đã nói về việc đảo ngược quyền sở hữu của luồng điều khiển, tức là người sở hữu trách nhiệm gọi các chức năng theo thứ tự mong muốn - cho dù đó là chức năng hay bạn nên đảo ngược nó với một thực thể bên ngoài.

Tuy nhiên, một khi OOP xuất hiện, mọi người bắt đầu nói về IoC trong bối cảnh OOP nơi các ứng dụng liên quan đến việc tạo đối tượng và các mối quan hệ của chúng, ngoài luồng điều khiển. Các ứng dụng này muốn đảo ngược quyền sở hữu của việc tạo đối tượng (chứ không phải luồng điều khiển) và yêu cầu một thùng chứa chịu trách nhiệm tạo đối tượng, vòng đời đối tượng và phụ thuộc vào các đối tượng ứng dụng do đó loại bỏ các đối tượng ứng dụng khỏi việc tạo đối tượng cụ thể khác.

Theo nghĩa đó, DI không giống như Io C , vì nó không liên quan đến luồng điều khiển, tuy nhiên nó là một loại Io * , tức là Đảo ngược quyền sở hữu của việc tạo đối tượng.

Điều gì sai trong cách giải thích của tôi về DI và IoC?


0

IoC hay còn gọi là Inversion of Control đề cập đến việc kiểm soát việc tạo các thể hiện đang được thực hiện bởi Spring container. Việc kiểm soát để tạo và xây dựng các đối tượng được container thực hiện cẩn thận. Container tạo các đối tượng và đưa chúng vào ứng dụng của chúng tôi.

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.