Hãy bán cho tôi trên các container IoC


17

Tôi đã thấy một số khuyến nghị sử dụng các bộ chứa IoC trong mã. Động lực rất đơn giản. Lấy mã phụ thuộc sau đây được tiêm:

class UnitUnderTest
{
    std::auto_ptr<Dependency> d_;
public:
    UnitUnderTest(
        std::auto_ptr<Dependency> d = std::auto_ptr<Dependency>(new ConcreteDependency)
    ) : d_(d)
    {
    }
};


TEST(UnitUnderTest, Example)
{
    std::auto_ptr<Dependency> dep(new MockDependency);
    UnitUnderTest uut(dep);
    //Test here
}

Vào:

class UnitUnderTest
{
    std::auto_ptr<Dependency> d_;
public:
    UnitUnderTest()
    {
        d_.reset(static_cast<Dependency *>(IocContainer::Get("Dependency")));
    }
};


TEST(UnitUnderTest, Example)
{
    UnitUnderTest uut;
    //Test here
}

//Config for IOC container normally
<Dependency>ConcreteDependency</Dependency>

//Config for IOC container for testing
<Dependency>MockDependency</Dependency>

(Trên đây là ví dụ C ++ giả thuyết)

Mặc dù tôi đồng ý rằng điều này đơn giản hóa giao diện của lớp bằng cách loại bỏ tham số hàm tạo phụ thuộc, tôi nghĩ rằng phương pháp chữa trị còn tệ hơn bệnh vì một vài lý do. Đầu tiên, và đây là một cái lớn đối với tôi, điều này làm cho chương trình của bạn phụ thuộc vào một tệp cấu hình bên ngoài. Nếu bạn cần triển khai nhị phân đơn, bạn chỉ đơn giản là không thể sử dụng các loại container này. Vấn đề thứ hai là API bây giờ yếu và tệ hơn, được gõ một cách nghiêm ngặt . Bằng chứng (trong ví dụ giả thuyết này) là đối số chuỗi cho bộ chứa IoC và kết quả trên kết quả.

Vì vậy, có những lợi ích khác của việc sử dụng các loại container này hay tôi chỉ không đồng ý với những người giới thiệu các container?


1
Mã mẫu trông giống như một ví dụ thực sự tồi tệ về việc triển khai IoC. Tôi chỉ quen thuộc với C # nhưng chắc chắn có một cách để xây dựng cấu hình tiêm và cấu hình lập trình trong C ++?
rmac

Câu trả lời:


12

Trong một ứng dụng lớn có nhiều lớp và nhiều bộ phận chuyển động, đó là nhược điểm bắt đầu trông khá nhỏ so với các ưu điểm.

Container không "đơn giản hóa giao diện" của lớp, nhưng nó làm như vậy theo một cách rất quan trọng. Container là một giải pháp cho vấn đề mà tiêm phụ thuộc tạo ra, đó là cần phải vượt qua các phụ thuộc ở mọi nơi, thông qua các biểu đồ đối tượng và trên các khu vực chức năng. Bạn có một ví dụ nhỏ ở đây có một phụ thuộc - điều gì xảy ra nếu đối tượng này có ba phụ thuộc và các đối tượng phụ thuộc vào nó có nhiều đối tượng phụ thuộc vào chúng , v.v. Không có thùng chứa, các đối tượng ở đầu các chuỗi phụ thuộc đó sẽ trở thành người chịu trách nhiệm theo dõi tất cả các phụ thuộc trong toàn bộ ứng dụng.

Có nhiều loại container khác nhau. Không phải tất cả chúng đều được gõ một cách nghiêm ngặt và không phải tất cả chúng đều yêu cầu các tệp cấu hình.


3
Nhưng một dự án lớn làm cho các vấn đề tôi đã đề cập tồi tệ hơn . Nếu dự án lớn, tệp cấu hình sẽ trở thành một nam châm phụ thuộc rất lớn và việc có một lỗi đánh máy dẫn đến hành vi không xác định khi chạy. (tức là có một lỗi đánh máy trong tệp cấu hình sẽ khiến diễn viên gây ra hành vi không xác định nếu trả về loại sai). Đối với sự phụ thuộc của phụ thuộc, những người không quan trọng ở đây. Hoặc nhà xây dựng quan tâm đến việc tạo ra chúng, hoặc thử nghiệm sẽ loại bỏ sự phụ thuộc cấp cao nhất.
Billy ONeal

... Tiếp tục ... Khi chương trình không được thử nghiệm, sự phụ thuộc cụ thể mặc định sẽ được khởi tạo ở mỗi bước. Wrt các loại container khác, bạn có một số ví dụ?
Billy ONeal

4
TBH Tôi không có nhiều kinh nghiệm với việc triển khai DI, nhưng hãy xem MEF trên .NET, có thể nhưng không phải gõ một cách nghiêm ngặt, không có tệp cấu hình và các cài đặt cụ thể của giao diện được "đăng ký" trên các lớp học BTW, khi bạn nói: "nhà xây dựng đảm nhận việc tạo ra chúng" - nếu đó là những gì bạn đang làm (còn gọi là "tiêm xây dựng của người nghèo"), thì bạn không cần một container. Ưu điểm của một container so với việc đó là container tập trung thông tin về tất cả các phụ thuộc đó.
nlawalker

+1 cho nhận xét cuối cùng đó - câu cuối cùng có câu trả lời :)
Billy ONeal

1
Câu trả lời tuyệt vời đã giúp tôi mò mẫm toàn bộ vấn đề. Vấn đề không chỉ đơn giản hóa nồi hơi, mà cho phép các yếu tố ở đầu chuỗi phụ thuộc cũng ngây thơ như các yếu tố ở phía dưới.
Christopher Berman

4

Khung Guice IoC từ Java không dựa vào tệp cấu hình mà dựa vào cấu hình . Điều này có nghĩa là cấu hình là mã không khác với mã tạo nên ứng dụng thực tế của bạn và có thể được cấu trúc lại, v.v.

Tôi tin rằng Guice là khung công tác Java IoC cuối cùng đã có cấu hình đúng.


Có ví dụ nào tương tự cho C ++ không?
Billy ONeal

@Billy, tôi không đủ quen thuộc với C ++ để có thể nói.

0

Câu trả lời SO tuyệt vời này của Ben Scheirman nêu chi tiết một số ví dụ mã trong C #; Một số lợi thế của container IoC (DI) là:

  • Chuỗi phụ thuộc của bạn có thể trở nên lồng nhau, và nó nhanh chóng trở nên khó sử dụng để nối chúng bằng tay.
  • Cho phép sử dụng lập trình định hướng Aspect .
  • Giao dịch cơ sở dữ liệu khai báo & lồng nhau.
  • Đơn vị khai báo & lồng nhau của công việc.
  • Ghi nhật ký.
  • Điều kiện trước / đăng (Thiết kế theo hợp đồng).

1
Tôi không thấy bất kỳ điều nào trong số những điều đó không thể được thực hiện bằng cách tiêm constructor đơn giản.
Billy ONeal

Với một thiết kế tốt, tiêm constructor hoặc phương pháp khác có thể là đủ cho bạn; những lợi thế của các container IoC này có thể chỉ trong các trường hợp cụ thể. Ví dụ được đưa ra với INotifyPropertyChanged trong dự án WPF là một ví dụ như vậy.
dodgy_coder
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.