2010-04-15 47 views
10

Tôi đã đọc gần đây về DI và IoC trong C++. Tôi là một chút bối rối (ngay cả sau khi đọc câu hỏi liên quan ở đây trên SO) và đã hy vọng cho một số làm rõ.Sự khác nhau giữa Inversion of Control và Dependency injection trong C++ là gì?

Dường như với tôi rằng việc làm quen với STL và Boost dẫn đến việc sử dụng tiêm phụ thuộc khá nhiều. Ví dụ: giả sử tôi đã thực hiện một chức năng tìm thấy giá trị trung bình của một dải số:

template <typename Iter> 
double mean(Iter first, Iter last) 
{ 
    double sum = 0; 
    size_t number = 0; 
    while (first != last) 
    { 
     sum += *(first++); 
     ++number; 
    } 
    return sum/number; 
}; 

Đây có phải là (nghĩa là sử dụng trình vòng lặp thay vì truy cập bộ sưu tập phụ thuộc)? Đảo ngược kiểm soát? Cũng không?

Hãy xem một ví dụ khác. Chúng tôi có một lớp học:

class Dice 
{ 
public: 
    typedef boost::mt19937 Engine; 
    Dice(int num_dice, Engine& rng) : n_(num_dice), eng_(rng) {} 
    int roll() 
    { 
     int sum = 0; 
     for (int i = 0; i < num_dice; ++i) 
      sum += boost::uniform_int<>(1,6)(eng_); 
     return sum; 
    } 
private: 
    Engine& eng_; 
    int n_; 
}; 

Điều này có vẻ như tiêm phụ thuộc. Nhưng nó đảo ngược kiểm soát?

Ngoài ra, nếu tôi thiếu điều gì đó, ai đó có thể giúp tôi không? Điều này có vẻ là cách tự nhiên để làm mọi thứ, vì vậy nếu đó là tất cả những gì có là Dependency Injection, tại sao mọi người lại gặp khó khăn khi sử dụng nó?

+1

Bạn đã đọc wiki chưa? Nó có một định nghĩa rất rõ ràng về IoC/DI http://en.wikipedia.org/wiki/Inversion_of_control – CDSO1

+6

Trong C++, chúng ta không làm IoC hoặc DI - chúng ta có những khái niệm riêng của chúng ta. –

+0

Chức năng mẫu của bạn có thể chia cho số không nếu bạn không cẩn thận. –

Trả lời

14

Inversion of Control là khái niệm rất chung chung, với các ý nghĩa khác nhau tùy thuộc vào loại "kiểm soát" mà bạn đang nói đến. Dependency injection là một dạng cụ thể.

Inversion of Control và lặp

Trong trường hợp này "kiểm soát" có nghĩa là "kiểm soát dòng chảy".

Tôi nghĩ ví dụ đầu tiên của bạn liên quan đến lặp lại không thực sự đảo ngược kiểm soát, bởi vì mã đó thực hiện kiểm soát luồng một cách rõ ràng. Đảo ngược điều khiển sẽ tách hành động để thực hiện từ điều khiển luồng. Nó có thể trông giống như thế này (tha thứ cho java/C# của tôi):

SumVisitor sumVisitor = new SumVisitor(); 
collection.AcceptVisitor(sumVisitor); 
int sum = sumVisitor.GetSum(); 

Đối tượng khách truy cập thực hiện điều gì đó cho mỗi thành phần bộ sưu tập mà nó truy cập, ví dụ: cập nhật trường đếm tổng. Nhưng không có điều khiển về cách thức hoặc thời điểm được gọi bởi bộ sưu tập, do đó, đảo ngược kiểm soát. Bạn cũng có thể triển khai MedianVisitor, MeanVisitor, MaximumVisitor, v.v. Mỗi cái thực hiện một giao diện IVisitor chung với phương thức Visit(Element).

Đối với bộ sưu tập, điều ngược lại là đúng: nó không có kiến ​​thức về những gì khách truy cập làm và đơn giản là chăm sóc kiểm soát luồng bằng cách gọi visitor.Visit(element) cho từng phần tử trong bộ sưu tập. Các triển khai khách truy cập khác nhau đều giống nhau cho bộ sưu tập.

Inversion of Control và đồ thị đối tượng xây dựng

Trong trường hợp này "kiểm soát" có nghĩa là "kiểm soát cách các thành phần được tạo ra và nối với nhau".

Trong bất kỳ ứng dụng không tầm thường nào, mã được chia thành các thành phần phải cộng tác. Để giữ cho các thành phần có thể tái sử dụng được, chúng không thể trực tiếp tạo ra các thành phần khác vì chúng sẽ gắn chúng vĩnh viễn với nhau. Thay vào đó, các thành phần riêng lẻ từ bỏ quyền kiểm soát trong quá trình xây dựng và kết nối thành phần.

Dependency injection là một cách để đạt được điều này, bằng cách tham chiếu đến đối tượng cộng tác viên trong hàm tạo. Sau đó, bạn cần một đoạn mã khởi động riêng biệt, nơi tất cả các thành phần được tạo và kết nối với nhau hoặc khuôn khổ tiêm phụ thuộc sẽ xử lý vấn đề này cho bạn. Lớp Dice của bạn thực sự là một ví dụ về tiêm phụ thuộc.

Một cách khác để từ bỏ quyền kiểm soát đối với việc xây dựng biểu đồ đối tượng là mẫu Service Locator, mặc dù nó có disadvantages.

1

Hãy để tôi cố gắng trả lời.

Ví dụ đầu tiên của bạn là không. Nó chỉ đơn giản là một mẫu.

Để được tiêm phụ thuộc, việc thực hiện sẽ phải được chọn và được cung cấp cho mẫu.

Vì nó là IoC, mẫu sẽ phải được cung cấp khi chạy (không biên dịch thời gian) cho loại thực hiện và được sử dụng như việc thực hiện hàm "mean()" (nghĩ về nhà máy cung cấp triển khai chức năng)

Ví dụ thứ hai của bạn trông giống như người tiêu dùng DI/IoC. Mã gửi việc thực thi Engine vào lớp của bạn sẽ là thành phần DI/IoC.

Hy vọng điều đó là chính xác và hữu ích.

Các vấn đề liên quan