How to avoid Singletons/global variables

Started by
21 comments, last by frob 7 years, 10 months ago
void CreateTexture(Texture *a_texture , string a_name)

Basically yes.

Generally you would want to use interface types instead of concrete types, but the idea is the same. "Injection" seems like an invasive or aggressive thing, it calls to my mind stabbing someone with needles who doesn't want it, but it isn't that at all. Normally it is just a parameter to the constructor, or a SetWhatever method.

Event listeners are a frequently-taught example. You create an interface and functions to add/remove listeners. Some other code implements that interface, then injects itself with TheTarget->AddListener(this);

In C++ the collection classes are another great example. All of them take an optional parameter of an allocator. You can use the default std::allocator, or you can inject your own custom allocator.

Another great example in C++ are associative containers and operations that take a comparison function. All of them use the default value of of the less-than operator. You can use the default, or you can inject your own comparison function.

In a nutshell, don't depend on concrete types. Depend on interfaces and allow other systems to pass those objects to you. They can pass them as parameters to the individual function, or as part of a constructor, or as part of an add/remove pair, or any other means you are comfortable with. The dependency inversion principle (linked to above) makes this pattern incredibly easy in the real world.

The key point is that you are using an object that can be easily replaced rather than a hard-coded specific or global object.

Advertisement

Generally you would want to use interface types instead of concrete types, but the idea is the same.

so if I'm correct I need to add a abstract class for the Texture.

But then it still does not make sense. these are the things I understand from this pattern

1.If we create a Ioc container class is will be easily for us to see what things can be init first, instead of digging into different classes and see what they are init.

2.While I'm include things my texture class does not need "#include<resourceLoader.h>" , so later on I can put this texture class into another other project it will work

But there still some things I don't understand

1. Of my understanding, more code == more bugs + more test case + use more time to read the code

2. If I wanted to include my resoruceLoader and texture class into other project I would need to copy 4 files , but then using singleton I just need to copy 2 files, which means I need to remember more filenames, seems not worth.

3. Is IResourceLoader == Ioc container ?

4. Still don't really understand about the interface types, because if I'm 100% sure I'm not going to delete or rename my texture class, why do I still need a abstract class for the texture, if not what can happen ?

5.What should I call/name my abstract class ?

The dependency inversion problem is a different problem from the singleton/static problem.

For the names of interfaces, a very common pattern is to name it based on what it solves, or if it is just an interfaced based on a concrete type, prefix with an I. Someone could later make a new texture class but they need to implement the ITexture interface. Your Texture class could implement the ITexture class and you could even have perfect correspondence between the public methods of Texture and the interface of ITexture if you wanted. Then when you write the code accept an ITexture pointer, manipulate ITexture pointers, and don't touch the concrete Texture class object.

But getting back to the static issue, that was answered well enough on the previous page. Texture resources are specific to the graphics contexts, and are often met with the common combination of loader/cache/proxy/pool. No static members. No static objects. No global objects.

This topic is closed to new replies.

Advertisement