Dependency injection ; good practices to reduce boilerplate code

I have a simple question, and I’m not even sure it has an answer but let’s try.
I’m coding in C++, and using dependancy injection to avoid global state. This works quite well, and I don’t run in unexpected/undefined behaviours very often.

However I realise that, as my project grows I’m writing a lot of code which I consider boilerplate. Worse : the fact there is more boilerplate code, than actual code makes it sometimes hard to understand.

Nothing beats a good example so let’s go :

I have a class called TimeFactory which creates Time objects.

For more details (not sure it’s relevant) : Time objects are quite complex because the Time can have different formats, and conversion between them is neither linear, nor straightforward. Each “Time” contains a Synchronizer to handle conversions, and to make sure they have the same, properly initialized, synchronizer, I use a TimeFactory. The TimeFactory has only one instance and is application wide, so it would qualify for singleton but, because it’s mutable, I don’t want to make it a singleton

In my app, a lot of classes need to create Time objects. Sometimes those classes are deeply nested.

Let’s say I have a class A which contains instances of class B, and so on up to class D. Class D need to create Time objects.

In my naive implementation, I pass the TimeFactory to the constructor of class A, which passes it to the constructor of class B and so on until class D.

Now, imagine I have a couple of classes like TimeFactory and a couple of class hierarchies like the one above : I loose all the flexibility and readability I’m suppose to get using dependancy injection .

I’m starting to wonder if there isn’t a major design flaw in my app …
Or is this a necessary evil of using dependancy injection ?

What do you think ?

5

In my app, a lot of classes need to create Time objects

Seems that your Time class is a very basic data type which should belong to the “general infrastructure” of your application. DI does not work well for such classes. Think about what it means if a class like string had to be injected into every part of the code which uses strings, and you would need to use a stringFactory as the only possibilty of creating new strings – the readability of your program would decrease by an order of magnitude.

So my suggestion: don’t use DI for general datatypes like Time. Write unit tests for the Time class itself, and when its done, use it everywhere in your program, just like the string class, or a vector class or any other class of the standard lib. Use DI for components which should be really decoupled one from each other.

5

What do you mean by “I loose all the flexibility and readability I’m suppose to get using dependency injection” – DI isn’t about readability. It’s about decoupling the dependency between objects.

It sounds like you have Class A creating Class B, Class B creating Class C and Class C creating Class D.

What you should have is Class B injected in to Class A. Class C injected in to Class B. Class D injected in to Class C.

3

I’m not sure why you don’t want to make your time factory a singleton. If there’s only one instance of it in your whole app, it is de facto a singleton.

That being said, it is very dangerous to share a mutable object, except if it’s properly guarded by synchronize blocks, in which case, there’s no reason for it not to be a singleton.

If you want to do dependency injection, you might want to look at spring or other dependency injection frameworks, which would allow you to auto assign parameters using an annotation

2

This aims to be a complementary answer to Doc Brown, and also to respond to unanswered comments of Dinaiz that are still related to the Question.

What you probably need is a framework for doing DI. Having complex hierarchies does not necessarily means bad design, but if you have to inject a TimeFactory bottom-up (from A to D) instead of injecting directly to D then probably there’s something wrong with the way you are doing Dependency Injection.

A singleton? No thanks. If you need only one istance make it shared across your application context (Using a IoC container for DI like Infector++ requires just to bind TimeFactory as single istance), here’s the example (C++11 by the way, but so C++. Maybe move to C++11 already? You get Leak-Free application for free):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>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>();
</code>
<code>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>(); </code>
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>();

Now the good point of a IoC container is that you don’t need to pass time factory up to D. if your class “D” need time factory, just put time factory as constructor parameter for class D.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>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
</code>
<code>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 </code>
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

as you see you inject TimeFactory only once. How to use “A”? Very simple, every class is injected, builded in the main or istantiated with a factory.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
</code>
<code>auto myA1 = ioc.build<A>(); //A is not "single" so many different istances auto myA2 = ioc.build<A>(); //can live at same time </code>
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time

every time you create class A it will be automatically (lazy istantiation) injected with all dependencies up to D and D will be injected with TimeFactory, so by calling only 1 method you have your complete hierarchy ready (and even complex hierachies are solved this way removing A LOT of boiler plate code): You don’t have to call “new/delete” and that’s very important because you can separate application logic from glue code.

D can create Time objects with informations that only D can have

That’s easy, your TimeFactory have a “create” method, then just use a different signature “create(params)” and you are done. Parameters that are no dependencies are often resolved this way. This also remove the duty of injecting things like “strings” or “integers” because that just add extra boiler plate.

Who creates who? IoC container creates istances and factories, the factories creates the rest (factories can create different objects with arbitrary parameters, so you don’t really need a state for factories). You can still use the factories as wrappers for the IoC Container: generally speaking Injectin the IoC Container is very bad and is the same of using a service locator. Some people solved the problem by wrapping the IoC Container with a factory (this is not strictly necessary, but has the advantage that the hierarchy is solved by the Container and all your factories becomes even easier to maintain).

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>//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);
}
</code>
<code>//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); } </code>
//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); 
}

Also don’t abuse dependency injection, simple types can just be class’ members or local scoped variables. This seem obvious but I saw people injecting “std::vector” just because there was a DI framework that allowed that. Always remember Demeter’s law: “Inject only what you really need to inject”

1

Do your A, B and C classes also need to create Time instances, or only class D? If it’s only class D, then A and B should know nothing about TimeFactory. Create an instance of TimeFactory inside C class, and pass it to class D. Note that by “create an instance” I don’t necessarily mean that the C class has to be responsible for instantiating the TimeFactory. It can receive DClassFactory from class B, and DClassFactory knows how to create Time instance.

A technique that I also often use when I don’t have any DI framework is providing two constructors, one which accepts a factory, and another one which creates a default factory. The second one has usually a protected/package access, and is used mainly for unit tests.

0

I implemented yet another C++ dependency
injection framework, which recently was proposed for boost – https://github.com/krzysztof-jusiak/di –
library is macro less (free), header only, C++03/C++11/C++14 library providing type safe, compile time, macro free constructor dependency injection.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật