Dependency Injection and Singleton Design Template

How to determine when to use dependency injection or a singleton pattern. I read a lot of sites on which they say: "Use dependency for singleton pattern." But I'm not sure if I agree with them. For my small or medium sized projects, I definitely see that using a singleton template is simple.

For example, Logger. I could use Logger.GetInstance().Log(...) But instead, why would I introduce every class I create with a log instance?

+56
oop design-patterns dependency-injection
Apr 18 '10 at 15:55
source share
7 answers

If you want to check what is logged in the test, you need dependency injection. In addition, a registrar is rarely a single — usually you have a registrar for each of your classes.

Check out this object-oriented design presentation for verification, and you'll see why singletones are bad.

The problem with single points is that they represent a global state that is difficult to predict, especially in tests.

Keep in mind that an object can be de facto single, but can still be obtained through dependency injection, and not through Singleton.getInstance() .

I will simply list some important points made by Mishko Hevery in his speech. After viewing, you will get a complete idea of ​​why it is better to define an object, what are its dependencies, but not to determine how to create them.

+50
Apr 18 '10 at 16:00
source share

Singletons are like communism: they both sound great on paper, but in practice they explode with problems.

The syntax pattern creates a disproportionate emphasis on the ease of access to objects. It completely avoids the context by requiring every consumer to use an object with an AppDomain scope, leaving no options for various implementations. It injects infrastructure knowledge into your classes (calling GetInstance() ) while adding exactly zero expressive power. This actually reduces your expressive power, because you cannot change the implementation used by one class without changing it for all of them. You simply cannot add one-time functions.

In addition, when the Foo class depends on Logger.GetInstance() , Foo effectively hides its consumer dependencies. This means that you cannot fully understand Foo or use it with certainty unless you read its source and find out that it depends on Logger . If you don’t have a source, this limits how well you can understand and effectively use the code you depend on.

A syntax pattern implemented with static properties / methods is nothing more than a hack infrastructure implementation. This limits you in a variety of ways, without offering any obvious advantages over alternatives. You can use it however you want, but since there are viable alternatives that promote better design, this should never be a recommended practice.

+71
Apr 18 '10 at 16:41
source share
Others have well explained the problem with singles in general. I just wanted to add a note about a specific Logger case. I agree with you that it is usually not a problem to access the Logger (or the root logger, to be precise), as it is solid using the static method getInstance() or getRootLogger() . (unless you want to know what is being registered by the class you are testing), but, in my experience, I can hardly recall such cases when it was necessary. Again for others, this may be a more pressing issue).

IMO, as a rule, a singleton logger is not a concern, since it does not contain any state related to the class you are testing. That is, the state of the registrar (and its possible changes) does not affect the state of the tested class. Thus, it does not make testing your device difficult.

An alternative would be to enter the registrar through the constructor so that (almost) every single class in your application. For interface consistency, you should enter it even if the class in question does not register anything at present - an alternative would be that when you find at some point that you now need to register something from this class, you need a logger, so so you need to add a constructor parameter for the DI, breaking all the client code. I don’t like both of these options, and I feel that using DI for registration will simply complicate my life to fit the theoretical rule without any particular benefit.

So, my bottom line: a class that is (almost) used universally but does not contain a state that matches your application can be safely implemented as Singleton .

+13
Apr 18 2018-10-18T00:
source share

This is mainly, but not for tests. Singltons were popular because they were easy to consume, but there are a number of drawbacks to singles.

  • It’s hard to check. The point is, how can I make sure that the log works correctly.
  • Hard to test. If I test code using a registrar, but that is not the focus of my test, I still need to ensure that my env test supports the registrar
  • Sometimes you don’t need a singleton, but more flexible

DI gives you easy consumption of your dependent classes - just put it in the args constructor and the system will give it to you, giving you the flexibility of testing and design.

+7
Apr 18 '10 at 16:10
source share

The only time you should use Singleton instead of Injection Dependency is that Singleton represents an immutable value, such as List.Empty or the like (assuming it is an immutable list).

A colon check for Singleton should be "would it be nice if it were a global variable instead of Singleton?" If not, you are using the Singleton template to work on a global variable and should take a different approach into account.

+1
Apr 18 '10 at 22:19
source share

Just checked an article by Monostate - this is a great alternative to singleton, but it has some simpler properties:

 class Mono{ public static $db; public function setDb($db){ self::$db = $db; } } class Mapper extends Mono{ //mapping procedure return $Entity; public function save($Entity);//requires database connection to be set } class Entity{ public function save(){ $Mapper = new Mapper(); $Mapper->save($this);//has same static reference to database class } $Mapper = new Mapper(); $Mapper->setDb($db); $User = $Mapper->find(1); $User->save(); 

Isn't that scary - because Mapper really depends on connecting to the database to execute save () - but if another mapper was previously created, it can skip this step when acquiring its dependencies. While trim, it's also a little messy, isn't it?

+1
Apr 24 '10 at 13:19
source share

There are other alternatives to the Singleton templates: Proxy and MonoState.

http://www.objectmentor.com/resources/articles/SingletonAndMonostate.pdf

How to use proxy template to replace singlet?

0
Apr 21 '10 at 12:29
source share



All Articles