S
S
skosterin882016-10-25 23:19:43
C++ / C#
skosterin88, 2016-10-25 23:19:43

What is the advantage of Dependency Injection over using the new operator?

Greetings dear Toaster community.
Recently discovered Dependency Injection. I read a bunch of articles on this topic on the internet, but did not understand what its charm is. I decided to take a practical example. Let's say we have a kind of game in which we deal with soldier units. The soldiers have weapons. A general description of the weapon is contained in the IWeapon interface:

public interface IWeapon
    {
        int Ammo { get; set; }
        string Name { get; }
        void Fire();
    }

The general description of the soldier is stored in the ISoldier interface:
public interface ISoldier
    {
        string Type { get; }
        IWeapon Weapon { get; set; }
        void Move();
    }

There are two implementations of the IWeapon interface: AssaultRifle and MachineGun. Accordingly, there are two implementations of the ISoldier interface: Rifleman and MachineGunner. Setting weapons for them is done in their constructors as follows:
public class Rifleman : ISoldier
    {
        private IWeapon _weapon;
        public Rifleman()
        {
            _weapon = new AssaultRifle();
        }
        ...
    }

    public class MachineGunner : ISoldier
    {
        private IWeapon _weapon;
        public MachineGunner()
        {
            _weapon = new MachineGun();
        }
        ...
    }

This is how the creation of class instances and their use looks in the Main() function:
//Классический случай
            ISoldier rifleman = new Rifleman();
            ISoldier machineGunner = new MachineGunner();

            for (int i = 0; i < 10; i++)
            {
                rifleman.Weapon.Fire();
                machineGunner.Weapon.Fire();
            }

If you use Dependency Injection through the same Ninject, then here's how I have to do it:
public class AssaultRifleConfigModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IWeapon>().To<AssaultRifle>();
        }
    }

    public class MachineGunConfigModule : NinjectModule
    {

        public override void Load()
        {
            Bind<IWeapon>().To<MachineGun>();
        }
    }
    public class RiflemanConfigModule : NinjectModule
    {
        public override void Load()
        {
            Bind<ISoldier>().To<Rifleman>();
        }
    }

    public class MachineGunnerConfigModule : NinjectModule
    {

        public override void Load()
        {
            Bind<ISoldier>().To<MachineGunner>();
        }
    }

    public class Rifleman : ISoldier
    {
        ...
        public Rifleman()
        {
            IKernel weaponKernel = new StandardKernel(new AssaultRifleConfigModule());
            _weapon = weaponKernel.Get<IWeapon>();
        }
        ...
    }
  
    public class MachineGunner : ISoldier
    {
        ...
        public MachineGunner()
        {
            IKernel weaponKernel = new StandardKernel(new MachineGunConfigModule());
            _weapon = weaponKernel.Get<IWeapon>();
        }
        ...
    }
    ...
    static void Main(string[] args)
    {
            ...
            //DI через NInject
            IKernel soldierKernel = new StandardKernel(new RiflemanConfigModule());
            ISoldier rifleman = soldierKernel.Get<ISoldier>();

            soldierKernel = new StandardKernel(new MachineGunnerConfigModule());
            ISoldier machineGunner = soldierKernel.Get<ISoldier>();

            for (int i = 0; i < 10; i++)
            {
                rifleman.Weapon.Fire();
                machineGunner.Weapon.Fire();
            }
    }

Question: how is the Dependency Injection method better than using the new operator in this situation?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey, 2016-10-26
Protko @Fesor

but I still don't understand what's wrong with it.

Don't do everything by hand. Describe the dependency graph and it will somehow assemble itself. That is, it can be even more correct to assemble the dependency graph by hand, but from the point of view of code readability, code maintainability (especially given the millions of dependencies in frameworks), and simply increasing the development speed, it is better to use some kind of container in main and request the top of the dependency graph there . And he'll figure it out.
In fact, the main thing is that your code does not know anything about the container. So that in one long winter evening you can easily replace everything with a "manual" assembly and you don't have to touch the code itself ... Well, annotations / attributes are already a compromise for convenience.

S
Stanislav Silin, 2016-10-26
@byme

Oh .. you piled up such garbage. Calling Get<> manually is not very good, everything has to be injected through a constructor or property. Read a little more about Dependency Injection (DI), you can understand it yourself)). Further there will be a wall of text, but it describes a real (supervisory in vacuum) situation.
Regarding the example. Here the nesting depth is not large and DI will only interfere. But let's imagine that you have a web server that waits for a request and returns some data. He must take this data from somewhere, a certain service named Service, which implements a certain IService interface, is kindly ready to provide us with it. For a correct Service robot, data is also needed, which it will convert and return to the one who asks for it. It gets them from SuperServiceHelper(ISuperServiceHelper) and SuperPuperServiceHelper(ISuperPuperServiceHelper). The first helper takes data from the SomeEntityRepository(ISomeEntityRepository) and SomeGreenEntityRepository(ISomeGreenEntityRepository) repositories. The second helper takes data from SomeBlueEntityRepository(ISomeBlueEntityRepository) and SomeRedEntityRepository(ISomeRedEntityRepository).
And so, you haven't forgotten where we started, after all this vahanalia (we still need all this to be covered with tests)? Oh yeah, we need a Service to process the request... We just fucking need a Service, here and now. This is where DI and IoC will save us, just say that you need IService and voila, this whole chain will be restored without our participation.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question