Điều này nhằm mục đích trở thành một câu trả lời bổ sung cho Doc Brown, và cũng để trả lời những bình luận chưa được trả lời của Dinaiz vẫn còn liên quan đến Câu hỏi.
Những gì bạn có thể cần là một khuôn khổ để làm DI. Có cấu trúc phân cấp phức tạp không nhất thiết có nghĩa là thiết kế tồi, nhưng nếu bạn phải tiêm từ dưới lên TimeFactory (từ A đến D) thay vì tiêm trực tiếp vào D thì có lẽ có gì đó không đúng với cách bạn đang thực hiện Dependency Injection.
Một người độc thân? Không, cám ơn. Nếu bạn chỉ cần một istance, hãy chia sẻ nó trong bối cảnh ứng dụng của bạn (Sử dụng bộ chứa IoC cho DI như Infector ++ chỉ cần liên kết TimeFactory dưới dạng một istance), đây là ví dụ (C ++ 11, nhưng C ++. đến C ++ 11 chưa? Bạn nhận được ứng dụng Leak-Free miễn phí):
Infector::Container ioc; //your app's context
ioc.bindSingleAsNothing<TimeFactory>(); //declare TimeFactory to be shared
ioc.wire<TimeFactory>(); //wire its constructor
// if you want to be sure TimeFactory is created at startup just request it
// (else it will be created lazily only when needed)
auto myTimeFactory = ioc.buildSingle<TimeFactory>();
Bây giờ, điểm hay của bộ chứa IoC là bạn không cần phải chuyển nhà máy thời gian lên D. nếu lớp "D" của bạn cần nhà máy thời gian, chỉ cần đặt nhà máy thời gian làm tham số hàm tạo cho lớp D.
ioc.bindAsNothing<A>(); //declare class A
ioc.bindAsNothing<B>(); //declare class B
ioc.bindAsNothing<D>(); //declare class D
//constructors setup
ioc.wire<D, TimeFactory>(); //time factory injected to class D
ioc.wire<B, D>(); //class D injected to class B
ioc.wire<A, B>(); //class B injected to class A
như bạn thấy bạn tiêm TimeFactory chỉ một lần. Làm thế nào để sử dụng "A"? Rất đơn giản, mỗi lớp được tiêm, xây dựng chính hoặc được xây dựng với một nhà máy.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
mỗi khi bạn tạo lớp A, nó sẽ tự động (istantiation lười biếng) được tiêm tất cả các phụ thuộc lên đến D và D sẽ được tiêm TimeFactory, do đó, chỉ bằng cách gọi 1 phương thức, bạn đã sẵn sàng phân cấp hoàn chỉnh (và thậm chí cả các thuật ngữ phức tạp được giải quyết theo cách này loại bỏ RẤT NHIỀU mã tấm nồi hơi): Bạn không phải gọi "mới / xóa" và điều đó rất quan trọng vì bạn có thể tách logic ứng dụng khỏi mã keo.
D có thể tạo các đối tượng Thời gian với thông tin mà chỉ D có thể có
Điều đó thật dễ dàng, TimeFactory của bạn có phương thức "tạo", sau đó chỉ cần sử dụng một chữ ký khác "tạo (params)" và bạn đã hoàn thành. Các thông số không phụ thuộc thường được giải quyết theo cách này. Điều này cũng loại bỏ nhiệm vụ tiêm những thứ như "chuỗi" hoặc "số nguyên" bởi vì chỉ cần thêm tấm nồi hơi.
Ai tạo ra ai? IoC container tạo ra các istances và nhà máy, các nhà máy tạo ra phần còn lại (các nhà máy có thể tạo ra các đối tượng khác nhau với các tham số tùy ý, vì vậy bạn không thực sự cần một trạng thái cho các nhà máy). Bạn vẫn có thể sử dụng các nhà máy làm trình bao bọc cho IoC Container: nói chung, việc tiêm chích vào IoC Container rất tệ và giống như sử dụng công cụ định vị dịch vụ. Một số người đã giải quyết vấn đề bằng cách bọc IoC Container với một nhà máy (điều này không thực sự cần thiết, nhưng có lợi thế là hệ thống phân cấp được giải quyết bởi Container và tất cả các nhà máy của bạn thậm chí còn dễ bảo trì hơn).
//factory method
std::unique_ptr<myType> create(params){
auto istance = ioc->build<myType>(); //this code's agnostic to "myType" hierarchy
istance->setParams(params); //the customization you needed
return std::move(istance);
}
Cũng không lạm dụng tiêm phụ thuộc, các loại đơn giản chỉ có thể là thành viên của lớp hoặc biến trong phạm vi cục bộ. Điều này có vẻ hiển nhiên nhưng tôi thấy mọi người tiêm "std :: vector" chỉ vì có một khung DI cho phép điều đó. Luôn nhớ luật của Demeter: "Chỉ tiêm những gì bạn thực sự cần tiêm"